<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko"><generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator><link href="https://nnoco.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://nnoco.github.io/" rel="alternate" type="text/html" hreflang="ko" /><updated>2020-05-17T04:22:09+09:00</updated><id>https://nnoco.github.io/feed.xml</id><title type="html">Sentio, ergo sum</title><subtitle>nnoco의 블로그입니다.</subtitle><author><name>nnoco</name></author><entry><title type="html">Java Annotation in Action 5</title><link href="https://nnoco.github.io/dev/java/2020/05/17/Java-Annotation-in-Action-5.html" rel="alternate" type="text/html" title="Java Annotation in Action 5" /><published>2020-05-17T01:20:55+09:00</published><updated>2020-05-17T01:20:55+09:00</updated><id>https://nnoco.github.io/dev/java/2020/05/17/Java-Annotation-in-Action-5</id><content type="html" xml:base="https://nnoco.github.io/dev/java/2020/05/17/Java-Annotation-in-Action-5.html">&lt;p&gt;앞서 리플렉션으로 메서드, 파라미터 정보를 읽고 메서드를 호출하면서 애너테이션을 처리하는 방법을 살펴봤습니다. 끝에서 언급했듯 아래와 같은 문제점이 있었습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;타입 안전성을 해칠 가능성&lt;/li&gt;
  &lt;li&gt;안전하지 않은 메서드 이름&lt;/li&gt;
  &lt;li&gt;시그니처가 다른 메서드 지원이 어려움&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;충분히 원하는 기능을 구현했지만 여러 변경에 대해 용이한 구현은 아닙니다. 자바에서 제공하는 동적 프록시(Proxy)를 활용하면 같은 동작을 하는 코드를 수월하게 작성할 수 있습니다. 프록시는 “대리인”이라는 뜻의 사전적 의미를 가지며, 프로그래밍에서의 프록시도 그와 유사하게 원래의 대상 메서드를 프록시를 통해 대신해서 호출할 수 있습니다.&lt;/p&gt;

&lt;!-- https://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;
&lt;figure&gt;
    &lt;img src=&quot;/assets/images/2020/05-17_aia5/normal_call.png&quot; alt=&quot;figure 1. 일반적인 메서드 호출&quot; /&gt;
    &lt;figcaption&gt;figure 1. 일반적인 메서드 호출&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!-- https://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;
&lt;figure&gt;
    &lt;img src=&quot;/assets/images/2020/05-17_aia5/proxy_call.png&quot; alt=&quot;figure 2. 프록시를 통한 메서드 호출&quot; /&gt;
    &lt;figcaption&gt;figure 2. 프록시를 통한 메서드 호출&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;figure 1은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calculator.plus(1, 2)&lt;/code&gt;와 같이 일반적인 방법으로 메서드를 호출할 때의 관계를 보여주고 있습니다. figure 2 프록시를 통해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plus&lt;/code&gt; 메서드를 호출할 때의 관계이며, 클라이언트는 프록시의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plus&lt;/code&gt; 메서드를 호출하게 되고 다시 프록시 객체는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt; 객체의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plus&lt;/code&gt; 메서드를 호출하게 됩니다.
프록시를 통해 호출할 때 메서드 호출 전/후의 처리와 메서드 호출 제어를 할 수 있게 됩니다.&lt;/p&gt;

&lt;p&gt;자바의 프록시는 표준 JDK에 내장되어 있어 별도의 라이브러리를 추가하지 않아도 되며 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.lang.reflect.Proxy&lt;/code&gt; 클래스를 활용해서 프록시 기능을 사용하게 됩니다.&lt;/p&gt;

&lt;p&gt;새로운 프록시 인스턴스를 생성하기 위해서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Proxy.newProxyInstance&lt;/code&gt; 정적 메서드를 호출합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newProxyInstance&lt;/code&gt; 메서드는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClassLoader&lt;/code&gt;, 인터페이스의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 배열 그리고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InvocationHandler&lt;/code&gt; 객체를 필요로 합니다. 프록시 클래스는 지정된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClassLoader&lt;/code&gt;에 정의되며, 두 번째 인자인 인터페이스의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 배열로 전달한 모든 인터페이스를 구현합니다. 이 때 배열은 인터페이스로만 구성되어야 하고 인터페이스 외의 클래스나 열거형 등의 타입은 전달할 수 없습니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InvocationHandler&lt;/code&gt; 인터페이스에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invoke&lt;/code&gt; 메서드가 정의되어 있습니다. 이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invoke&lt;/code&gt; 메서드가 프록시 객체를 통해 호출되는 모든 메서드를 처리하게 됩니다. 이 때 클라이언트가 호출한 메서드가 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Method&lt;/code&gt; 타입의 파라미터로 전달되고, 인자 역시 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object[]&lt;/code&gt; 타입으로 받게 됩니다.&lt;/p&gt;

&lt;p&gt;아래는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.lang.Runnable&lt;/code&gt; 인터페이스의 프록시 인스턴스를 생성하는 예시입니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// RunnableProxy.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.InvocationHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.Method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.Proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RunnableProxy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runnable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;newProxyInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClassLoader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;},&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;InvocationHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
                    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Throwable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; 메서드 호출&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
        
        &lt;span class=&quot;n&quot;&gt;runnable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runnable&lt;/code&gt; 변수에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Runnable&lt;/code&gt; 인터페이스를 구현한 프록시 객체가 담겨 있으며, 일반적인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Runnable&lt;/code&gt; 인터페이스를 구현한 객체처럼 호출 할 수 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run&lt;/code&gt; 메서드를 호출하면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run&lt;/code&gt; 메서드의 정보가 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invoke&lt;/code&gt; 메서드에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;method&lt;/code&gt; 파라미터로 전달됩니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;method&lt;/code&gt; 파라미터는 4편에서 썼던 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Method&lt;/code&gt;와 동일하며, 메서드를 실행하기 위해서는 실제 객체가 필요합니다. (위의 예시에서는 프록시가 아닌 실제 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Runnable&lt;/code&gt; 객체가 없으므로 실행할 수 없습니다.) 그리고 메서드를 호출하면서 전달한 인자가 있다면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;args&lt;/code&gt; 파라미터로 받을 수 있습니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;프록시를-활용한-log-애너테이션-처리&quot;&gt;프록시를 활용한 @Log 애너테이션 처리&lt;/h2&gt;
&lt;p&gt;Java Annotation in Action 4편의  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Ignore&lt;/code&gt; 애너테이션은 그대로 사용하고, 프록시 객체는 인터페이스에 대해서만 생성할 수 있으므로, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ICalculator&lt;/code&gt;  인터페이스를 작성하고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt; 클래스에서는 해당 인터페이스를 구현하도록 수정해 보겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Calculator.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.github.nnoco.annotation_in_action.ch4.Ignore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.github.nnoco.annotation_in_action.ch4.Log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ICalculator 인터페이스를 구현합니다.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Calculator&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ICaculator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;plus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;minus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// ICalculator.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.github.nnoco.annotation_in_action.ch4.Log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.github.nnoco.annotation_in_action.ch4.Ignore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ICaculator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;plus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 애너테이션은 인터페이스의 메서드에 태그합니다.&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Log&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;minus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@Ignore&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;기존의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt; 클래스의 메서드를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ICalculator&lt;/code&gt; 인터페이스로 옮긴 후 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implements ICalculator&lt;/code&gt;를 추가해 줍니다. 이 때 태그되어 있던 애너테이션은 인터페이스 쪽으로 옮겨 줍니다. 프록시에서는 인터페이스의 메서드 정보만을 알고 있으므로, 인터페이스를 구현한 클래스의 애너테이션은 알지 못합니다. 이제 인터페이스는 준비되었으므로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InvocationHandler&lt;/code&gt; 구현 클래스를 작성할 차례입니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InvocationHandler&lt;/code&gt;를 구현하는 클래스는 로그를 출력하고 실제 객체의 메서드를 호출해야 하므로 프록시 대상 객체를 담아둘 멤버 변수를 정의하고, 생성자를 통해 초기화하도록 합니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// LogProxy.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.github.nnoco.annotation_in_action.ch4.Ignore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.github.nnoco.annotation_in_action.ch4.Log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.InvocationHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.Method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.Parameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.Proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.stream.Collectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.stream.IntStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LogProxy&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;InvocationHandler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LogProxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Throwable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logAnnotationPresented&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isAnnotationPresent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Log 애너테이션이 있으면 메서드를 호출하기 전에 파라미터를 로그로 출력&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logAnnotationPresented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameterLog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getParameterLog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getParameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; 메서드 시작. &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameterLog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 리플렉션을 통해 메서드 실행&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Log 애너테이션이 있으면 리턴 값을 출력&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logAnnotationPresented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; 메서드 끝. &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 값 반환&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getParameterLog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Parameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IntStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;boxed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// Ignore 애너테이션이 태그되지 않은 파라미터만 필터합니다.&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isAnnotationPresent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ignore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;

                &lt;span class=&quot;c1&quot;&gt;// &quot;파라미터 이름=인자&quot;를 반환합니다.&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// 바이트코드에 파라미터 이름이 유지되어야 파라미터 이름을 얻을 수 있고,&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// 그렇지 않은 경우 argN 형식의 이름을 반환합니다.&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Collectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;joining&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InvocationHandler&lt;/code&gt; 인터페이스를 구현했으므로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invoke&lt;/code&gt; 메서드를 구현하는 것 이외에 기존의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CalculatorReflection.calculateWithLog&lt;/code&gt; 메서드와 큰 차이점은 없습니다. 다만 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invoke&lt;/code&gt; 메서드가 파라미터로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;method&lt;/code&gt;와 인자인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;args&lt;/code&gt;를 받게 되므로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 정보로부터 실행할 메서드를 찾는 과정이 없어졌습니다. 또한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt; 클래스에만 국한되지 않고 모든 타입에 대해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogProxy&lt;/code&gt;를 적용할 수 있도록 했습니다.&lt;/p&gt;

&lt;p&gt;작성한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogProxy&lt;/code&gt;를 테스트 해 봅시다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// LogProxyTest.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.Proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LogProxyTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ICalculator&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ICalculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;newProxyInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClassLoader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ICalculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;},&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LogProxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()));&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;calculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Proxy.newProxyInstance&lt;/code&gt; 메서드를 통해 프록시 객체를 생성합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ICalculator&lt;/code&gt; 인터페이스를 전달하고, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogProxy&lt;/code&gt; 객체를 생성하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InvocationHandler&lt;/code&gt;를 전달합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Proxy.newProxyInstance&lt;/code&gt; 메서드의 반환 타입을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ICalculator&lt;/code&gt; 타입으로 형변환 해 주는데, 이 때 구현 타입인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt; 타입으로 형변환을 하면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClassCastException&lt;/code&gt;이 발생하므로 주의해야 합니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogProxyTest&lt;/code&gt;의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; 메서드를 실행해 보면 이 전의 로그 처리와 동일하게 동작하는 것을 확인할 수 있고, 이제 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt;가 아닌 다른 타입에 대해서도 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션 처리를 할 수 있게 되었습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 실행 결과
minus 메서드 시작. operand1=1
minus 메서드 끝. -1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;여기까지 Java Annotation in Action 3, 4, 5편을 통해 리플렉션과 리플렉션을 이용해 애너테이션을 읽고 처리하는 방법을 다뤄봤습니다. 클래스나 생성자 등 아직 다루지 않은 리플렉션의 영역들이 있지만 시리즈의 나머지 편에서 보다 실용적인 예제들과 함께 리플렉션의 추가적인 내용을 다뤄보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;* 작성한 코드는 &lt;a href=&quot;https://github.com/nnoco/java-annotation-in-action/tree/master/src/io/github/nnoco/annotation_in_action/ch5&quot;&gt;GitHub Repository&lt;/a&gt;에서 확인하실 수 있습니다.&lt;/p&gt;

&lt;hr /&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html&quot;&gt;https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/java-dynamic-proxies&quot;&gt;https://www.baeldung.com/java-dynamic-proxies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>nnoco</name></author><category term="Java" /><category term="Annotation" /><category term="APT" /><category term="PAPA" /><category term="Reflection" /><category term="Proxy" /><summary type="html">앞서 리플렉션으로 메서드, 파라미터 정보를 읽고 메서드를 호출하면서 애너테이션을 처리하는 방법을 살펴봤습니다. 끝에서 언급했듯 아래와 같은 문제점이 있었습니다.</summary></entry><entry><title type="html">Java Annotation in Action 4</title><link href="https://nnoco.github.io/dev/java/2020/05/16/Java-Annotation-in-Action-4.html" rel="alternate" type="text/html" title="Java Annotation in Action 4" /><published>2020-05-16T21:31:34+09:00</published><updated>2020-05-16T21:31:34+09:00</updated><id>https://nnoco.github.io/dev/java/2020/05/16/Java-Annotation-in-Action-4</id><content type="html" xml:base="https://nnoco.github.io/dev/java/2020/05/16/Java-Annotation-in-Action-4.html">&lt;p&gt;Java Annotation in Action 3편에서는 필드에 애너테이션을 태그하여 필드의 값을 체크해 봤습니다. 이번 편에서는 리플렉션을 통해 메서드와 파라미터의 애너테이션을 다뤄봅니다.&lt;/p&gt;

&lt;p&gt;메서드의 경우에도 필드를 가져올 때와 유사하게 대상 클래스의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 객체를 얻고, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt;의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getMethod(String, Class...)&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getMethods()&lt;/code&gt; 메서드나 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getDeclaredMethod(String, Class...)&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getDeclaredMethods()&lt;/code&gt; 메서드를 이용해 클래스에 정의되어 있는 메서드를 가져올 수 있습니다.&lt;/p&gt;

&lt;p&gt;먼저 간단한 계산을 할 수 있는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt; 클래스를 작성합니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Calculator.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Calculator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;plus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt; 클래스에 정의된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plus&lt;/code&gt; 메서드를 리플렉션을 통해 가져오기 위해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CalculatorReflection&lt;/code&gt; 클래스를 작성해 봅시다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// CalculatorReflection.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.Method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CalculatorReflection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getPlusMethodBySeveralWays&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// getMethod(이름, 파라미터 타입 가변인자)로 plus 메서드를 가져옵니다.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 해당 클래스에 정의된 public 메서드 또는 상속 받은 public 메서드만 가져올 수 있습니다.&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plus1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;plus&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// getMethods()로 모든 메서드 목록을 배열로 가져옵니다.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 해당 클래스에 정의된 public 메서드 또는 상속 받은 public 메서드만 가져올 수 있습니다.&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methods1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMethods&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// getDeclaredMethod(이름, 파라미터 타입 가변인자)로 plus 메서드를 가져옵니다.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 상속 받은 메서드는 해당되지 않으며 해당 클래스에 정의된 메서드만 가져옵니다.&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plus2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDeclaredMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;plus&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// getDeclaredMethods()로 모든 메서드 목록을 배열로 가져옵니다.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 상속 받은 메서드는 해당되지 않으며 해당 클래스에 정의된 메서드만 가져옵니다.&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methods2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDeclaredMethods&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;메서드는 이름과 파라미터 타입을 지정하여 하나의 메서드를 가져오거나 클래스의 모든 메서드를 배열로 가져올 수 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getMethod()&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getMethods()&lt;/code&gt;의 경우 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt;인 메서드만 반환하며, 부모로부터 상속 받은 메서드도 포함됩니다. 반면에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getDeclaredMethod()&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getDeclaredMethods()&lt;/code&gt;는 접근 제어 지시자와 상관없이 모든 메서드를 가져올 수 있지만 상속 받은 메서드는 포함되지 않습니다. 즉 자기 자신에게 정의된 메서드만 반환합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plus&lt;/code&gt; 메서드는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt;이고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt; 클래스에 정의되어 있으므로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getMethod()&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getDeclaredMethod()&lt;/code&gt; 구분없이 두 가지 방법으로 모두 가져올 수 있습니다.&lt;/p&gt;

&lt;p&gt;특정 메서드 하나만을 반환하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getMethod()&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getDeclaredMethod()&lt;/code&gt;는 메서드의 이름뿐만 아니라 메서드의 파라미터 타입을 가변인자로 전달 받습니다. 자바에서는 메서드 파라미터 타입과 개수가 다르게 하여 메서드 오버로딩을 할 수 있으므로, 오버로딩된 메서드 중 찾고자 하는 메서드를 특정하기 위해서는 메서드의 이름과 파라미터 타입이 필요하기 때문입니다.&lt;/p&gt;

&lt;p&gt;이제 메서드와 파라미터에 애너테이션을 사용하기 위해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Ignore&lt;/code&gt; 애너테이션을 정의해 보겠습니다. 뒤에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션이 태그된 메서드를 호출하면 메서드의 파라미터와 반환 값을 로그로 출력해볼 것입니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Ignore&lt;/code&gt; 애너테이션은 파라미터에 태그하여 로그로 출력하지 않을 때 사용합니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Log.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;METHOD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Log&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Ignore.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PARAMETER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Ignore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;두 애너테이션 작성이 완료되었으면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt; 클래스에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;minus&lt;/code&gt; 메서드를 추가하고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Ignore&lt;/code&gt; 애너테이션을 태그해 줍니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Calculator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// plus 생략&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Log&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;minus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@Ignore&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CalculatorReflection&lt;/code&gt; 클래스에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calculateWithLog&lt;/code&gt; 메서드를 추가해 주겠습니다. 이 메서드는 실행할 메서드의 이름과 해당 메서드를 실행할 때 전달할 인자 값을 전달받아서 메서드를 찾고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션이 있으면 메서드의 호출 전과 후에 로그를 출력합니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// CalculatorReflection.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.Method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.Parameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.stream.Collectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.stream.IntStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CalculatorReflection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 기존 코드 생략&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;calculateWithLog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Calculator&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logAnnotationPresented&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isAnnotationPresent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 처리하기 용이하도록 파라미터를 배열로 묶습니다.&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Log 애너테이션이 있으면 메서드를 호출하기 전에 파라미터를 로그로 출력&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logAnnotationPresented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameterLog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getParameterLog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getParameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; 메서드 시작. &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameterLog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 리플렉션을 통해 메서드 실행&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;calculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Log 애너테이션이 있으면 리턴 값을 출력&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logAnnotationPresented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; 메서드 끝. &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 값 반환&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getParameterLog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Parameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IntStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;boxed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// Ignore 애너테이션이 태그되지 않은 파라미터만 필터합니다.&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isAnnotationPresent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ignore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;

                &lt;span class=&quot;c1&quot;&gt;// &quot;파라미터 이름=인자&quot;를 반환합니다.&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// 바이트코드에 파라미터 이름이 유지되어야 파라미터 이름을 얻을 수 있고,&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// 그렇지 않은 경우 argN 형식의 이름을 반환합니다.&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Collectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;joining&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;한 번에 모든 코드를 작성하여 코드가 긴 느낌이 있지만 하나씩 살펴보도록 하겠습니다. 먼저 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calculateWithLog&lt;/code&gt; 메서드는 인자로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Calculator&lt;/code&gt; 클래스의 인스턴스와 실행할 메서드의 이름(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plus&lt;/code&gt; 또는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;minus&lt;/code&gt;), 그리고 메서드에 전달할 인자인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operand1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operand2&lt;/code&gt;를 전달 받습니다. 이 메서드는 결과적으로 원하는 메서드를 실행하면서, 메서드에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션이 태그되어 있으면 메서드 실행 전에 파라미터를 로그로 출력하고, 실행 후에 결과를 로그로 출력합니다.&lt;/p&gt;

&lt;p&gt;먼저 앞서 살펴본 방법으로 실행할 메서드를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class.getMethod()&lt;/code&gt;를 호출하여 가져옵니다. 그리고 필드에 있는 애너테이션 태그 여부를 확인할 때와 마찬가지로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isAnnotationPresent()&lt;/code&gt; 메서드를 호출하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션이 태그되어 있는지 확인합니다.&lt;/p&gt;

&lt;p&gt;그 다음 줄에서는 인자로 전달할 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operand1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operand2&lt;/code&gt;를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; 배열로 묶어주는데, 이는 파라미터를 로그로 출력할 때와 메서드를 호출할 때의 편의를 위함입니다. 메서드의 파라미터는 배열로 표현되기 때문에, 동일한 인덱스로 접근할 수 있게 하기 위해 인자도 배열로 묶습니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션이 태그 되어 있는 경우에는 메서드를 호출하기 전에 아래에 작성한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getParameterLog&lt;/code&gt; 메서드를 호출하여 파라미터와 인자를 로그로 출력합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getParameterLog&lt;/code&gt; 메서드를 살펴보면 파라미터에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Ignore&lt;/code&gt; 애너테이션 태그 여부를 확인하기 위해 메서드와 마찬가지로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isAnnotationPresent&lt;/code&gt; 메서드를 호출하여 확인합니다. 이 때 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Ignore&lt;/code&gt; 애너테이션이 있으면 해당 파라미터는 로그를 출력하지 않도록 하기 위해서 스트림에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter&lt;/code&gt;를 통해 걸러내 줍니다.&lt;/p&gt;

&lt;p&gt;그리고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Parameter&lt;/code&gt; 클래스는 파라미터의 이름을 반환하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getName()&lt;/code&gt; 메서드가 있습니다. 이 메서드는 파라미터의 이름을 반환하지만, 컴파일 시에 별다른 옵션이 없으면 소스 상의 파라미터의 이름은 제거되어 이 경우 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;argN&quot;&lt;/code&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;arg0&quot;&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;arg1&quot;&lt;/code&gt;, …) 형식으로 반환합니다. 실제 파라미터 이름을 얻기 위해서는 자바 컴파일 시 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-parameters&lt;/code&gt;를 추가해 주어야 합니다.&lt;/p&gt;

&lt;p&gt;다시 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calculateWithLog&lt;/code&gt; 메서드로 돌아와서 메서드를 실행하는 부분을 살펴봅시다. 실행할 메서드의 이름을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; 파라미터로 전달 받고 있어서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt;문이나 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt; 구문을 이용해 호출을 분기해 줄 수도 있지만, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Method&lt;/code&gt; 클래스의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invoke&lt;/code&gt; 메서드를 이용해 리플렉션을 통해 메서드를 실행할 수도 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invoke&lt;/code&gt; 메서드는 해당 메서드가 실행될 실제 객체와 메서드가 실행될 때 필요한 인자를 가변인자로 전달 받습니다. 일반적인 방법으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;caculate.plus(1, 2)&lt;/code&gt;와 같이 메서드를 실행할 때도 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Caculator&lt;/code&gt; 클래스의 객체가 필요하듯이 리플렉션을 통해 메서드를 실행하더라도 실제 객체가 필요합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;method.invoke()&lt;/code&gt; 함수에 전달하는 객체는 해당 메서드가 있는 객체여야 합니다. 인자는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; 타입의 가변인자를 전달받습니다. 이 때 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; 배열을 전달할 수도 있으므로 위에서 정의해 둔 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arguments&lt;/code&gt; 변수를 사용합니다.&lt;/p&gt;

&lt;p&gt;그리고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invoke&lt;/code&gt;의 반환 타입은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; 이므로 원래의 타입인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;long&lt;/code&gt;으로 캐스팅 하고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result&lt;/code&gt; 변수에 담아줍니다. 그 후 파라미터와 마찬가지로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션이 있는 경우 리턴 값을 로그로 출력해준 다음 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result&lt;/code&gt;를 반환해 줍니다.&lt;/p&gt;

&lt;p&gt;작성한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;caculateWithLog&lt;/code&gt; 메서드를 테스트하기 위해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; 메서드를 아래와 같이 작성해 줍니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CalculatorReflection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 기존 코드 생략&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Calculator&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;CalculatorReflection&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculatorReflection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CalculatorReflection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// plus 메서드는 @Log가 없으므로 로그가 출력되지 않습니다.&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculatorReflection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;calculateWithLog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;calculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;plus&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;// minus 메서드는 @Log가 있으므로 로그가 출력됩니다.&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;minus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculatorReflection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;calculateWithLog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;calculator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;minus&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plus&lt;/code&gt; 메서드에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션이 태그되어 있지 않으므로 아무런 로그도 출력되지 않습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션을 태그한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;minus&lt;/code&gt; 메서드는 아래와 같이 로그가 출력되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;minus 메서드 시작. arg0=1
minus 메서드 끝. -1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이번 편에서는 리플렉션을 통해 메서드와 파라미터를 읽고, 메서드를 실행해 보고 메서드와 파라미터에 태그된 애너테이션을 읽고 처리해 보았습니다. 위의 코드를 다듬어 조금 더 범용적인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calculateWithLog&lt;/code&gt; 메서드를 만들 수 있지만 본질적으로 아래와 같은 문제가 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;타입 안전성을 해칠 가능성
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plus&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;minus&lt;/code&gt; 메서드는 동일한 파라미터 타입과 리턴 타입을 가지고 있지만, 다른 메서드를 지원하기 위해 코드를 수정하면 안전하지 않은 타입을 갖게 될 수 있습니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;안전하지 않은 메서드 이름
    &lt;ul&gt;
      &lt;li&gt;메서드 이름을 문자열로 전달하므로 잘못된 문자열 이름을 전달하게 될 수 있습니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;시그니처가 다른 메서드 지원이 어려움
    &lt;ul&gt;
      &lt;li&gt;파라미터의 갯수가 한정적이고, 리턴 타입도 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;long&lt;/code&gt;으로 고정되어 있습니다. 가변인자와 제너릭을 사용해 해결할 수는 있지만 제한적입니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이러한 문제를 해결하기 위해서는 다음 편에서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.lang.reflect&lt;/code&gt; 패키지의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Proxy&lt;/code&gt; 클래스를 활용해 동일한 기능을 다이내믹 프록시로 구현해 보도록 하겠습니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;* 작성한 코드는 &lt;a href=&quot;https://github.com/nnoco/java-annotation-in-action/tree/master/src/io/github/nnoco/annotation_in_action/ch4&quot;&gt;GitHub Repository&lt;/a&gt;에서 확인하실 수 있습니다.&lt;/p&gt;</content><author><name>nnoco</name></author><category term="Java" /><category term="Annotation" /><category term="APT" /><category term="PAPA" /><category term="Reflection" /><summary type="html">Java Annotation in Action 3편에서는 필드에 애너테이션을 태그하여 필드의 값을 체크해 봤습니다. 이번 편에서는 리플렉션을 통해 메서드와 파라미터의 애너테이션을 다뤄봅니다.</summary></entry><entry><title type="html">Java Annotation in Action 3</title><link href="https://nnoco.github.io/dev/java/2020/05/06/Java-Annotation-in-Action-3.html" rel="alternate" type="text/html" title="Java Annotation in Action 3" /><published>2020-05-06T20:11:31+09:00</published><updated>2020-05-06T20:11:31+09:00</updated><id>https://nnoco.github.io/dev/java/2020/05/06/Java-Annotation-in-Action-3</id><content type="html" xml:base="https://nnoco.github.io/dev/java/2020/05/06/Java-Annotation-in-Action-3.html">&lt;p&gt;Java Annotation in Action 1편과 2편에서는 애너테이션의 개념과 정의 방법을 알아보았습니다. 이번 편에서는 소스 코드에 태그된 애너테이션을 자바 리플렉션을 통해 숨을 불어 넣어줄 차례입니다. 애너테이션을 읽어 필요한 로직을 작성하는 것을 애너테이션 프로세싱(Annotation Processing)이라고 하며, 컴파일 타임과 런타임에 애너테이션 프로세싱을 할 수 있으며, 런타임에는 자바의 리플렉션을 이용합니다.&lt;/p&gt;

&lt;h1 id=&quot;1-리플렉션reflection&quot;&gt;1. 리플렉션(Reflection)&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%B0%98%EC%98%81_(%EC%BB%B4%ED%93%A8%ED%84%B0_%EA%B3%BC%ED%95%99)&quot;&gt;위키피디아&lt;/a&gt;에서 리플렉션은 다음과 같이 정의하고 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;컴퓨터 프로그램에서 런타임 시점에 사용되는 자신의 구조와 행위를 관리(type introspection)하고 수정할 수 있는 프로세스를 의미한다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;자바의 리플렉션은 클래스의 상속/구현 관계, 클래스를 구성하고 있는 생성자, 멤버 변수, 멤버 메서드 등과 클래스, 멤버 등에 태그된 &lt;strong&gt;애너테이션&lt;/strong&gt;을 읽어 올 수 있고, 읽는 것 뿐만 아니라 클래스의 새로운 인스턴스를 생성하거나, 멤버 변수의 값을 바꾸거나, 메서드를 실행하는 등의 기능을 수행할 수 있습니다.&lt;/p&gt;

&lt;p&gt;이러한 정보는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.lang.Class&lt;/code&gt; 클래스의 인스턴스로 표현되며, 아래의 방법으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 인스턴스를 가져올 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// class 키워드를 사용&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 객체의 getClass() 메서드를 호출&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, World!&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Class 클래스의 forName() static 메서드를 호출&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;forName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;java.lang.String&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;상황에 맞는 방법으로 대상 클래스의 정보를 갖고 있는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 객체를 가져올 수 있고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 객체가 리플렉션의 시작점이 됩니다. 참고로 위의 코드에서 변수 이름을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clazz&lt;/code&gt;로 한 이유는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt;가 자바의 키워드이므로 변수 이름으로 사용할 수 없기 때문입니다.&lt;/p&gt;

&lt;p&gt;이 글에서는 리플렉션의 모든 내용을 다루지 않고 애너테이션 처리에 초점을 맞춰 필요한 기능들을 사용하며 설명을 더하도록 하겠습니다.&lt;/p&gt;

&lt;h1 id=&quot;2-유효성-검증-애너테이션-예제&quot;&gt;2. 유효성 검증 애너테이션 예제&lt;/h1&gt;
&lt;p&gt;객체의 유효성 검증을 위한 몇 가지 애너테이션을 만들고 이를 검증하는 애너테이션 처리를 개발해 보겠습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NotNull&lt;/code&gt; 애너테이션을 정의한 후 클래스의 멤버 변수에 태그하여 해당 멤버 변수가 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;이 아닌지 체크하도록 합니다.&lt;/p&gt;

&lt;p&gt;먼저 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NotNull&lt;/code&gt; 애너테이션입니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// io.github.nnoco.annotation_in_action.ch3.validation.NotNull.java&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;validation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * 멤버 변수가 null이 아님을 체크하는 애너테이션
 */&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;FIELD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NotNull&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;런타임에도 애너테이션이 유지되도록 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Retention(RetentionPolicy.RUNTIME)&lt;/code&gt;을 태그하고, 멤버 변수에만 한정적으로 태그할 수 있도록 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Target(ElementType.FIELD)&lt;/code&gt;를 태그해 주었습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;message&lt;/code&gt; 요소를 정의하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;인 경우에 표시할 메시지를 작성할 수 있도록 하고 기본 값을 두어 꼭 전달하지 않아도 사용할 수 있게 하였습니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NotNull&lt;/code&gt; 애너테이션을 사용하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Book&lt;/code&gt; 클래스입니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;validation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * 책 정보 클래스
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@NotNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;title은 필수 항목입니다.&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@NotNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;author는 필수 항목입니다.&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getTitle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setTitle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 이하 Getter, Setter 생략&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;책 정보를 관리하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Book&lt;/code&gt; 클래스는 제목(title), 저자(author), 가격(price)을 가지고 있으며, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;author&lt;/code&gt; 필드를 필수 값으로 지정하였습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NotNull&lt;/code&gt;애너테이션의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;message&lt;/code&gt;에 적절한 메시지를 입력하여, 어느 필드에서 유효성 검증을 통과하지 못했는지 알 수 있도록 합니다.&lt;/p&gt;

&lt;p&gt;이제 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotNullValidator&lt;/code&gt; 클래스를 작성하고 리플렉션으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NotNull&lt;/code&gt; 애너테이션이 태그된 필드의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; 여부를 체크해 봅시다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// io.github.nnoco.annotation_in_action.ch3.validation.NotNullValidator.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;validation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.reflect.Field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.Objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * {@link NotNull}이 태그된 필드의 null 여부를 체크하는 유효성 검사기
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NotNullValidator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/**
     * 전달된 객체의 NotNull 유효성을 검증합니다.
     * @param object 유효성을 검사할 객체
     * @throws IllegalArgumentException @NotNull을 태그한 필드의 값이 null인 경우
     * @throws NullPointerException {@code object}가 null인 경우
     */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;NullPointerException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;object는 null일 수 없습니다.&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 전달된 객체의 Class 객체 가져오기&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 해당 클래스에 정의된 모든 필드 가져오기&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clazz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDeclaredFields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Field&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;field:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// 필드에 태그된 NotNull 애너테이션 가져오기(없으면 null)&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;NotNull&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;notNull&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAnnotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;NotNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// @NotNull 애너테이션이 태그되어 있는 경우&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nonNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;notNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;validateField&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;notNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;validateField&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Field&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NotNull&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;notNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 필드의 값 가져오기&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getFieldValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// 필드의 값이 null이라면 예외 발생&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IllegalArgumentException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;notNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getFieldValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Field&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// private 접근 제어 지시자를 무시하도록 accessible을 true로 설정&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;accessible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isAccessible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAccessible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 필드의 값 가져오기&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// object 객체의 field 필드의 값 조회&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;IllegalAccessException&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// 필드에 접근할 수 없는 경우 발생 - accessible을 변경하여 발생하지 않음&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printStackTrace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 원래의 accessible로 설정&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAccessible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accessible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;유효성 검증이 필요한 객체에 대해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotNullValidator&lt;/code&gt;의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate&lt;/code&gt; 메서드를 호출하여 유효성을 검증하고 유효성 검증에 실패한 경우 즉, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NotNull&lt;/code&gt;이 태그 되어 있는 필드의 값이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;인 경우 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IllegalArgumentException&lt;/code&gt;을 발생시킵니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotNullValidator&lt;/code&gt; 클래스를 자세히 살펴보겠습니다.&lt;/p&gt;

&lt;p&gt;1. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&amp;lt;?&amp;gt; clazz = object.getClass();&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate&lt;/code&gt; 메서드에 전달된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;object&lt;/code&gt; 객체의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getClass()&lt;/code&gt; 메서드를 호출하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 객체를 가져옵니다. 이 때 object가 null이면 NullPointerException이 발생하므로 앞에서 먼저 object에 대한 null 체크를 먼저 수행해 줍니다.&lt;/p&gt;

&lt;p&gt;2. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field[] fields = clazz.getDeclaredFields();&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field&lt;/code&gt; 클래스는 필드의 이름, 값 등을 가져올 수 있는 정보를 가지고 있습니다. 이러한 필드를 가져오기 위해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 클래스에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getDeclaredFields()&lt;/code&gt; 메서드가 정의되어 있습니다. 이 메서드는 접근 플래그(private, protected, default)에 상관없이 클래스에 정의된 모든 필드를 배열로 반환합니다. 이 때 상속된 필드는 해당되지 않으므로 상속된 필드를 가져오기 위해서는 부모 클래스의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 객체를 가져와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getDeclaredFields()&lt;/code&gt; 메서드를 호출해야 합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getFields()&lt;/code&gt; 메서드는 상속받은 필드를 가져올 수 있지만 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; 필드에만 해당됩니다. 이 예제에서는 상속받은 필드는 제외하도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;3. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotNull notNull = field.getAnnotation(NotNull.class);&lt;/code&gt; 
필드에 태그된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NotNull&lt;/code&gt; 애너테이션을 가져오는 부분입니다. 보이는 것처럼 리플렉션을 통해 가져온 애너테이션은 객체로 표현되고, 애너테이션에 정의된 요소에 전달한 값은 메서드를 호출하여 얻을 수 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAnnotation()&lt;/code&gt; 메서드는 Java 5에 추가된 메서드로 Java 8에 추가된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt;을 지원하지 않습니다. 이를 위해 Java 8에서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAnnotationsByType()&lt;/code&gt; 메서드가 추가되었습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAnnotation()&lt;/code&gt; 메서드는 애너테이션이 태그되어 있으면 해당 애너테이션의 객체를 반환하고 없으면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;을 반환합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Book&lt;/code&gt; 클래스의 경우 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;author&lt;/code&gt;에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NotNull&lt;/code&gt;이 태그되어 있으므로 해당 애너테이션을 가져올 수 있습니다.&lt;/p&gt;

&lt;p&gt;4. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;field.setAccessible(true);&lt;/code&gt;&lt;br /&gt;
필드의 accessible은 필드에 접근할 수 있는지 여부를 나타냅니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt; 필드의 경우 기본적으로 접근할 수 없습니다. 따라서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setAccessible(true)&lt;/code&gt;를 호출해 주어 접근 가능하도록 만들고, 뒤에서 필드의 값을 가져올 수 있도록 합니다. 만약 이런 식으로 객체의 캡슐화를 깨고 싶지 않다면 해당 필드의 값을 반환하는 Getter 메서드를 호출하여 값을 가져오도록 할 수도 있습니다.&lt;/p&gt;

&lt;p&gt;5. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value = field.get(object);&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get()&lt;/code&gt; 메서드를 이용해 특정 객체의 필드에 담긴 값을 가져올 수 있습니다. 이 때 실제 객체를 인자로 넘겨줄 수 있으며, 해당 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;field&lt;/code&gt;가 정의된 객체여야 합니다. 만약 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;field&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;object&lt;/code&gt;가 올바르지 않다면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IllegalArgumentException&lt;/code&gt;이 발생하며, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;field&lt;/code&gt;에 접근 할 수 없는 경우에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IllegalAccessException&lt;/code&gt;이 발생합니다. 4번의 과정에서 accessible을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ture&lt;/code&gt;로 설정했으므로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IllegalAccessException&lt;/code&gt;은 발생하지 않고 정상적으로 값을 가져올 수 있습니다.&lt;/p&gt;

&lt;p&gt;끝으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validateField&lt;/code&gt; 메서드에서 필드의 값이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;인지 체크하고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;이라면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IllegalArgumentException&lt;/code&gt;을 발생시킵니다. 이 때 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IllegalArgumentException&lt;/code&gt;의 인자로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NotNull&lt;/code&gt; 애너테이션의 인스턴스인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notNull&lt;/code&gt;의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;message()&lt;/code&gt;를 호출하여 애너테이션을 태그할 때 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;message&lt;/code&gt; 요소에 전달한 메시지를 전달합니다.&lt;/p&gt;

&lt;h1 id=&quot;3-notnullvalidator의-동작-확인&quot;&gt;3. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotNullValidator&lt;/code&gt;의 동작 확인&lt;/h1&gt;
&lt;p&gt;간단히 테스트할 수 있도록 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotNullValidatorTest&lt;/code&gt; 클래스를 작성하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotNullValidator&lt;/code&gt; 클래스가 정상적으로 동작하는지 확인해 보겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// io.github.nnoco.annotation_in_action.ch3.validation.NotNullValidatorTest.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation_in_action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ch3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;validation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * NotNullValidator 동작 확인
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NotNullValidatorTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IllegalAccessException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;NotNullValidator&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;validator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NotNullValidator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;book&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Java Annotation in Action&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;nnoco&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 유효한 객체이므로 통과&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;validator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setTitle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// title이 null이므로 예외 발생&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;validator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;첫 번째 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate()&lt;/code&gt; 메서드를 호출했을 때는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;과 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;author&lt;/code&gt;의 값이 있으므로 예외가 발생하지 않고 정상적으로 유효성 검증이 통과됩니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;의 값을 바꿔주고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate()&lt;/code&gt; 메서드를 호출하면 구현한 대로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IllegalArgumentException&lt;/code&gt;이 발생합니다.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Exception in thread &quot;main&quot; java.lang.IllegalArgumentException: title은 필수 항목입니다.
	at io.github.nnoco.annotation_in_action.ch3.validation.NotNullValidator.validateField(NotNullValidator.java:45)
	at io.github.nnoco.annotation_in_action.ch3.validation.NotNullValidator.validate(NotNullValidator.java:34)
	at io.github.nnoco.annotation_in_action.ch3.validation.NotNullValidatorTest.main(NotNullValidatorTest.java:18)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotNullValidator&lt;/code&gt;에서는 예외를 던지는 방식으로 구현했지만 입맛에 따라 올바르지 않은 필드의 목록을 반환하도록 할 수도 있을 것입니다. 또한 accessible을 강제로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;로 설정하여 필드의 값을 가져오도록 구현했는데, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NotNull&lt;/code&gt; 애너테이션에 해당 필드의 값을 반환하는 Getter의 이름을 전달하도록 하여 해당 Getter를 호출하도록 하거나, 필드의 이름으로 Getter이름을 만들어(title 필드의 경우 getTitle) Getter를 가져온 후 호출하는 방법 등이 있을 것입니다.&lt;/p&gt;

&lt;p&gt;이번 예제에서는 클래스의 필드에 태그된 애너테이션을 리플렉션을 통해 읽고 처리해보았습니다. 유사한 방법으로 클래스, 메서드, 파라미터 등에 태그된 애너테이션을 처리할 수 있으며 뒤에서 다양한 실습 예제를 통해 함께 다뤄보도록 하겠습니다.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;위 코드는 &lt;a href=&quot;https://github.com/nnoco/java-annotation-in-action/tree/master/src/io/github/nnoco/annotation_in_action/ch3/validation&quot;&gt;GitHub Repository&lt;/a&gt;에서 확인하실 수 있습니다.&lt;/p&gt;</content><author><name>nnoco</name></author><category term="Java" /><category term="Annotation" /><category term="APT" /><category term="PAPA" /><category term="Reflection" /><summary type="html">Java Annotation in Action 1편과 2편에서는 애너테이션의 개념과 정의 방법을 알아보았습니다. 이번 편에서는 소스 코드에 태그된 애너테이션을 자바 리플렉션을 통해 숨을 불어 넣어줄 차례입니다. 애너테이션을 읽어 필요한 로직을 작성하는 것을 애너테이션 프로세싱(Annotation Processing)이라고 하며, 컴파일 타임과 런타임에 애너테이션 프로세싱을 할 수 있으며, 런타임에는 자바의 리플렉션을 이용합니다.</summary></entry><entry><title type="html">Jekyll 타임존 이슈</title><link href="https://nnoco.github.io/blog/2020/05/02/Jekyll-%ED%83%80%EC%9E%84%EC%A1%B4-%EC%9D%B4%EC%8A%88.html" rel="alternate" type="text/html" title="Jekyll 타임존 이슈" /><published>2020-05-02T00:07:51+09:00</published><updated>2020-05-02T00:07:51+09:00</updated><id>https://nnoco.github.io/blog/2020/05/02/Jekyll-%ED%83%80%EC%9E%84%EC%A1%B4-%EC%9D%B4%EC%8A%88</id><content type="html" xml:base="https://nnoco.github.io/blog/2020/05/02/Jekyll-%ED%83%80%EC%9E%84%EC%A1%B4-%EC%9D%B4%EC%8A%88.html">&lt;p&gt;Jekyll은 포스트의 날짜 정보를 이용해 페이지 Path를 구성하는데, 이 때 URL의 날짜가 타임존에 따라서 포스트의 날짜보다 하루가 더 큰 경우가 있다. Front Matter에 Date가 없는 경우에는 파일 이름의 날짜를 이용하고 파일 이름의 날짜에는 시간 정보가 없으므로 차이가 없다.&lt;/p&gt;

&lt;p&gt;Front Matter에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;date&lt;/code&gt; 속성으로 일시를 직접 작성하는 경우에 나타나는데, 이 때 타임존 오프셋까지 설정해주면 해결된다.&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;2020-05-02 00:07:51+0900&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;원인을 파악하기 위해 검색하다가 보니 &lt;a href=&quot;https://github.com/jekyll/jekyll/issues/1069&quot;&gt;2013년에 작성된 Jekyll GitHub의 Issues&lt;/a&gt;에 있었는데, &lt;a href=&quot;https://github.com/jekyll/jekyll/issues/7550&quot;&gt;작년 2월의 이슈&lt;/a&gt;로도 등록되어 있고, Jekyll 3.8.5를 사용하는 나도 그런 걸 보면 해결하기 어려운 이슈인걸까.&lt;/p&gt;</content><author><name>nnoco</name></author><category term="Jekyll" /><category term="Timezone" /><category term="Wrong Path" /><summary type="html">Jekyll은 포스트의 날짜 정보를 이용해 페이지 Path를 구성하는데, 이 때 URL의 날짜가 타임존에 따라서 포스트의 날짜보다 하루가 더 큰 경우가 있다. Front Matter에 Date가 없는 경우에는 파일 이름의 날짜를 이용하고 파일 이름의 날짜에는 시간 정보가 없으므로 차이가 없다.</summary></entry><entry><title type="html">포스트에 Series 적용하기</title><link href="https://nnoco.github.io/blog/2020/05/01/%ED%8F%AC%EC%8A%A4%ED%8A%B8%EC%97%90-Series-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0.html" rel="alternate" type="text/html" title="포스트에 Series 적용하기" /><published>2020-05-01T22:08:01+09:00</published><updated>2020-05-01T22:08:01+09:00</updated><id>https://nnoco.github.io/blog/2020/05/01/%ED%8F%AC%EC%8A%A4%ED%8A%B8%EC%97%90-Series-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</id><content type="html" xml:base="https://nnoco.github.io/blog/2020/05/01/%ED%8F%AC%EC%8A%A4%ED%8A%B8%EC%97%90-Series-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0.html">&lt;p&gt;대개의 경우 글을 쓸 때 단편적인 글을 쓰지만 하나의 주제를 연재식으로 쓸 때가 있다. 이러한 &lt;strong&gt;시리즈&lt;/strong&gt;글은 태그나 카테고리로는 표현이 어려우므로 커스터마이징이 필요했다. 시리즈를 구현하기 위한 방법으로 커스텀 플러그인을 개발하거나 컬렉션 등을 활용할 수 있겠지만, 현재 블로그에서는 &lt;a href=&quot;https://jekyllrb-ko.github.io/docs/datafiles&quot;&gt;Jekyll의 데이터 파일&lt;/a&gt;을 활용해 구현하였다.&lt;/p&gt;

&lt;h1 id=&quot;데이터-파일&quot;&gt;데이터 파일&lt;/h1&gt;
&lt;p&gt;데이터 파일은 말그대로 사이트에서 사용할 데이터 파일로써 YAML, JSON, CSV, TSV 파일을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_data&lt;/code&gt; 디렉토리에 위치 시켜 Liquid에서 사용할 수 있다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_data&lt;/code&gt; 하위의 디렉토리를 구성하여 데이터의 네임스페이스를 적용할 수 있어서, 시리즈를 위한 데이터 파일은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_data/series&lt;/code&gt; 디렉토리에 위치 시켰다.&lt;/p&gt;

&lt;p&gt;아래는 “Java Annotation in Action” 시리즈의 데이터를 저장하기 위한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java_annotation_in_action.yaml&lt;/code&gt; 파일이다.&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Java Annotation in Action&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;posts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;애너테이션&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;소개'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/dev/java/2020/05/02/Java-Annotation-in-Action-1.html&lt;/span&gt;

  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;애너테이션&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;작성'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/dev/java/2020/05/02/Java-Annotation-in-Action-2.html&lt;/span&gt;

  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;리플렉션을&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;이용한&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;런타임&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;애너테이션&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;처리'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/dev/java/2020/05/02/Java-Annotation-in-Action-3.html&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;published&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 이하 생략&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;시리즈의 이름으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; 속성과 시리즈에 포함되는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;posts&lt;/code&gt; 속성을 정의하고, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;posts&lt;/code&gt; 하위에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;path&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;published&lt;/code&gt;(Optional)로 구성되는 배열을 정의했고, 이 구조를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post.html&lt;/code&gt; 레이아웃에서 사용하게 된다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;: 시리즈에 포함된 글의 제목&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;path&lt;/code&gt;: 해당 포스트의 상대 경로, 링크와 현재 페이지 비교 시 사용&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;published&lt;/code&gt;: 포스트의 발행 여부, 그 때 그 때 글을 작성하고 시리즈 파일에 추가할 수도 있겠지만 미리 목록으로 보여주고 싶은 경우를 위해 추가했다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;인 경우 링크는 걸지 않고 제목 뒤에 (예정) 텍스트를 보여준다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jekyll은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_post&lt;/code&gt; 디렉토리에 작성하더라도 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;published&lt;/code&gt;의 값을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;로 주면 글을 노출시키지 않기 때문에 미리 파일을 생성해둘 수 있다.&lt;/p&gt;

&lt;h1 id=&quot;포스트-헤더front-matter에-series-속성-추가&quot;&gt;포스트 헤더(Front Matter)에 series 속성 추가&lt;/h1&gt;
&lt;p&gt;데이터 파일을 이용해 시리즈 목록을 표시하는 방법은 포스트의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;series&lt;/code&gt; 속성에 정의한 이름으로 데이터 파일을 찾아 시리즈를 찾도록 한다. 이 때 데이터 파일의 경로, 확장자를 제외한 파일 이름을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;series&lt;/code&gt; 속성으로 설정한다. Java Annotation in Action 시리즈의 데이터 파일 이름은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java_annotation_in_action.yml&lt;/code&gt;이므로 작성하는 포스트의 헤더를 아래와 같이 작성한다.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;포스트 제목&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#...기타 속성 작성&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;java_annotation_in_action&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;post-레이아웃-수정&quot;&gt;Post 레이아웃 수정&lt;/h1&gt;
&lt;p&gt;Post 레이아웃에서 시리즈 목록을 보여줄 위치에 아래 코드를 추가해준다. 참고로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page&lt;/code&gt; 변수가 렌더링 될 글의 참조 변수이고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post&lt;/code&gt;는 시리즈의 포스트 데이터이다.&lt;/p&gt;

&lt;div class=&quot;language-liquid highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;!-- 페이지에 series 속성이 있는 경우에만 처리 --&amp;gt;
&lt;span class=&quot;p&quot;&gt;{%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;

&amp;lt;!-- data.series에서 페이지의 시리즈 이름으로 데이터를 가져옴 --&amp;gt;
&lt;span class=&quot;p&quot;&gt;{%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;
&amp;lt;div class=&quot;post-series&quot;&amp;gt;
    &amp;lt;header&amp;gt;&lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt; 시리즈&amp;lt;/header&amp;gt;
    &amp;lt;ol&amp;gt;
    &lt;span class=&quot;p&quot;&gt;{%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;series.posts&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;
    &amp;lt;li&amp;gt;
        &amp;lt;div&amp;gt;
        &lt;span class=&quot;p&quot;&gt;{%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;published&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;
        &amp;lt;!-- 시리즈 포스트의 published가 false인 경우에는 제목만 노출 --&amp;gt;
        &amp;lt;span class=&quot;series-not-published&quot;&amp;gt;&lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&amp;lt;/span&amp;gt;

        &lt;span class=&quot;p&quot;&gt;{%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;elsif&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;
        &amp;lt;!-- 렌더링 포스트와 시리즈 포스트의 경로가 같은 경우 제목만 노출 --&amp;gt;
        &amp;lt;span class=&quot;series-current&quot;&amp;gt;&lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&amp;lt;/span&amp;gt;

        &lt;span class=&quot;p&quot;&gt;{%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;
        &amp;lt;!-- 그 외의 경우에는 링크 설정 --&amp;gt;
        &amp;lt;a href=&quot;&lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&quot;&amp;gt;&lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&amp;lt;/a&amp;gt;
        &lt;span class=&quot;p&quot;&gt;{%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;endif&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/li&amp;gt;
    &lt;span class=&quot;p&quot;&gt;{%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;endfor&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;
    &amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&lt;span class=&quot;p&quot;&gt;{%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;endif&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;적용-결과&quot;&gt;적용 결과&lt;/h1&gt;
&lt;p&gt;적당히 CSS까지 적용한 후에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;series&lt;/code&gt; 속성이 있는 글에 표시되는 시리즈 목록은 아래와 같이 나타난다.&lt;/p&gt;

&lt;div class=&quot;post-series&quot;&gt;
    &lt;header&gt;Java Annotation in Action 시리즈&lt;/header&gt;
    &lt;ol&gt;
    
    &lt;li&gt;
        &lt;div&gt;&lt;a href=&quot;/dev/java/2020/05/01/Java-Annotation-in-Action-1.html&quot;&gt;애너테이션 소개&lt;/a&gt;
            
        &lt;/div&gt;
    &lt;/li&gt;
    
    &lt;li&gt;
        &lt;div&gt;&lt;a href=&quot;/dev/java/2020/05/01/Java-Annotation-in-Action-2.html&quot;&gt;애너테이션 작성&lt;/a&gt;
            
        &lt;/div&gt;
    &lt;/li&gt;
    
    &lt;li&gt;
        &lt;div&gt;&lt;a href=&quot;/dev/java/2020/05/06/Java-Annotation-in-Action-3.html&quot;&gt;리플렉션을 이용한 런타임 애너테이션 처리 - 필드편&lt;/a&gt;
            
        &lt;/div&gt;
    &lt;/li&gt;
    
    &lt;li&gt;
        &lt;div&gt;&lt;a href=&quot;/dev/java/2020/05/16/Java-Annotation-in-Action-4.html&quot;&gt;리플렉션을 이용한 런타임 애너테이션 처리 - 메서드편&lt;/a&gt;
            
        &lt;/div&gt;
    &lt;/li&gt;
    
    &lt;li&gt;
        &lt;div&gt;&lt;a href=&quot;/dev/java/2020/05/17/Java-Annotation-in-Action-5.html&quot;&gt;프록시를 이용한 애너테이션 처리&lt;/a&gt;
            
        &lt;/div&gt;
    &lt;/li&gt;
    
    &lt;li&gt;
        &lt;div&gt;&lt;span class=&quot;series-not-published&quot;&gt;@Autowired 따라잡기&lt;/span&gt;
        &lt;/div&gt;
    &lt;/li&gt;
    
    &lt;li&gt;
        &lt;div&gt;&lt;span class=&quot;series-not-published&quot;&gt;Netflix Feign 따라잡기&lt;/span&gt;
        &lt;/div&gt;
    &lt;/li&gt;
    
    &lt;li&gt;
        &lt;div&gt;&lt;span class=&quot;series-not-published&quot;&gt;Bean에 환경변수 설정하기&lt;/span&gt;
        &lt;/div&gt;
    &lt;/li&gt;
    
    &lt;li&gt;
        &lt;div&gt;&lt;span class=&quot;series-not-published&quot;&gt;컴파일 타임 애너테이션 처리&lt;/span&gt;
        &lt;/div&gt;
    &lt;/li&gt;
    
    &lt;li&gt;
        &lt;div&gt;&lt;span class=&quot;series-not-published&quot;&gt;부록&lt;/span&gt;
        &lt;/div&gt;
    &lt;/li&gt;
    
    &lt;/ol&gt;
&lt;/div&gt;

&lt;p&gt;Post 레이아웃에 적용한대로 현재 글, 다른 글, 발행되지 않은 글에 따라 다르게 적용이 되었고, 글 내용 자체에 포함이 되지 않으므로 발췌(excerpt)에도 포함되지 않는다.&lt;/p&gt;

&lt;h1 id=&quot;아쉬운-부분&quot;&gt;아쉬운 부분&lt;/h1&gt;
&lt;p&gt;데이터 파일을 이용해 간단하고 빠르게 시리즈를 적용할 수 있었지만, 어쨌든 글과 시리즈 데이터 파일을 따로 관리해야 한다는 불편함이 있다. GitHub에서 Jekyll을 호스팅 할 때 커스텀 플러그인 적용이 어렵지만 회피할 수 있는 방법이 있으므로 Jekyll Hook을 활용해서 자동으로 시리즈를 적용할 수 있는 방법을 고려해 보아야 겠다.&lt;/p&gt;</content><author><name>nnoco</name></author><category term="jekyll" /><category term="customizing" /><category term="series" /><summary type="html">대개의 경우 글을 쓸 때 단편적인 글을 쓰지만 하나의 주제를 연재식으로 쓸 때가 있다. 이러한 시리즈글은 태그나 카테고리로는 표현이 어려우므로 커스터마이징이 필요했다. 시리즈를 구현하기 위한 방법으로 커스텀 플러그인을 개발하거나 컬렉션 등을 활용할 수 있겠지만, 현재 블로그에서는 Jekyll의 데이터 파일을 활용해 구현하였다.</summary></entry><entry><title type="html">Java Annotation in Action 2</title><link href="https://nnoco.github.io/dev/java/2020/05/01/Java-Annotation-in-Action-2.html" rel="alternate" type="text/html" title="Java Annotation in Action 2" /><published>2020-05-01T20:43:29+09:00</published><updated>2020-05-01T20:43:29+09:00</updated><id>https://nnoco.github.io/dev/java/2020/05/01/Java-Annotation-in-Action-2</id><content type="html" xml:base="https://nnoco.github.io/dev/java/2020/05/01/Java-Annotation-in-Action-2.html">&lt;p&gt;1편에서 소개한 애너테이션은 필요에 따라 직접 정의하여 활용할 수 있습니다. 이러한 애너테이션을 사용자 정의(User Defined) 또는 커스텀(Custom) 애너테이션이라고 합니다. 애너테이션도 인터페이스, 클래스와 같은 하나의 타입이며, 인터페이스의 특성을 갖습니다. 이번 글에서는 애너테이션을 작성하기 위한 문법과 애너테이션의 특성을 부여하기 위한 자바 내장 애너테이션에 대해 다뤄보겠습니다.&lt;/p&gt;

&lt;h1 id=&quot;1-애너테이션-타입-문법&quot;&gt;1. 애너테이션 타입 문법&lt;/h1&gt;
&lt;p&gt;애너테이션은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@interface&lt;/code&gt; 키워드를 사용하여 정의합니다. 애너테이션 정의 내에 어떠한 요소도 포함하지 않는 가장 단순한 모습의 애너테이션은 아래와 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FirstAnnotation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;그리고 작성한 FirstAnnotation은 아래와 같이 태그할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@FirstAnnotation&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FirstAnnotationTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nd&quot;&gt;@FirstAnnotation&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;nd&quot;&gt;@FirstAnnotation&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;FirstAnnotationTest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;nd&quot;&gt;@FirstAnnotation&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@FirstAnnotation&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    	&lt;span class=&quot;nd&quot;&gt;@FirstAnnotation&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;greeting&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, Annotation!&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@FirstAnnotation&lt;/code&gt; 애너테이션은 위 코드에서와 같이 클래스, 멤버 변수, 메서드, 생성자, 파라미터, 로컬 변수와 패키지 정보 파일인 package-info.java 파일의 패키지 선언에도 태그할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// package-info.java 파일&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@FirstAnnotation&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nnoco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;2-애너테이션-타입의-요소element-추가&quot;&gt;2. 애너테이션 타입의 요소(Element) 추가&lt;/h1&gt;
&lt;p&gt;애너테이션 타입의 본문에는 메서드 선언을 포함할 수 있으며, 이러한 메서드 선언을 애너테이션의 요소라고 합니다. 애너테이션의 요소는 제한된 반환 타입을 가지며, 일반 파라미터, 타입 파라미터, throws 절을 포함할 수 없습니다. 의사 코드로 표현한 문법은 아래와 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[modifier] @interface &amp;lt;type_identifier&amp;gt; {
    [public abstract] &amp;lt;type&amp;gt; &amp;lt;element_identifier&amp;gt;() [default &amp;lt;elementValue&amp;gt;]; 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;대괄호로 감싼 부분은 생략 가능하고, 꺽쇠 괄호로 감싼 부분은 필수로 입력해야 하는 부분입니다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;modifier: 인터페이스의 지시자와 동일합니다.&lt;/li&gt;
  &lt;li&gt;type_identifier: 애너테이션 타입의 이름입니다.&lt;/li&gt;
  &lt;li&gt;요소의 지시자는 생략 가능하며, public, abstract, public abstract만 가능합니다.&lt;/li&gt;
  &lt;li&gt;type: 요소의 반환 타입입니다.&lt;/li&gt;
  &lt;li&gt;element_identifier: 애너테이션 타입 요소의 이름입니다.&lt;/li&gt;
  &lt;li&gt;default: 요소의 기본 값을 설정할 수 있으며 default 값의 형식으로 사용합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 중 요소가 반환하는 타입은 자바의 원시(Primitive) 타입, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enum&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Annotation&lt;/code&gt; 타입 및 그들의 1차원 배열만 가능하고 자기 자신을 반환 타입으로 갖거나 애너테이션 간 타입 참조 사이클을 가질 수 없습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 애너테이션 타입 자신을 요소의 반환 타입으로 사용하는 경우 - 컴파일 오류&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 타입 참조 사이클(상호 참조)이 발생하는 경우 - 컴파일 오류&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;애너테이션 타입의 요소의 개수에 따라 아래와 같이 명칭을 구분합니다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;마커 애너테이션(Marker Annotation): 요소가 없는 경우&lt;/li&gt;
  &lt;li&gt;단일 요소 애너테이션(Single-Element Annotation): 요소가 하나만 정의된 경우&lt;/li&gt;
  &lt;li&gt;일반 애너테이션: 2개 이상의 요소가 정의된 경우&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;위의 내용을 참고하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javax.validation&lt;/code&gt; 패키지의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Max&lt;/code&gt; 애너테이션처럼 최대 값을 제한하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@IntMax&lt;/code&gt; 애너테이션을 정의해 보겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Log.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Log&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 로그 레벨(0: Debug, 1: Info, 2: Warn, 3: Error&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// 로그 앞에 붙일 접두어&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// 반환 값도 로그로 출력할지 여부&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;logReturn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션 타입에는 로그 레벨을 설정하기 위한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;level&lt;/code&gt;, 로그 출력 시 메시지 앞에 붙일 접두어 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefix&lt;/code&gt;, 반환 값을 출력하기 위한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logReturn&lt;/code&gt; 요소가 선언되어 있으며, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;level&lt;/code&gt;과 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefix&lt;/code&gt;에는 기본 값이 있어 생략할 수 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션은 아래와 같이 사용합니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// LogTest.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LogTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// level, prefix는 기본 값이 있으므로 생략 가능&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// logReturn은 기본 값이 없으므로 생략 불가&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logReturn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;안녕하세요.&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;애너테이션은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@애너테이션(요소 = 값)&lt;/code&gt;의 형태로 사용할 수 있으며, 요소가 기본 값을 가지고 있는 경우에는 생략할 수 있습니다.&lt;/p&gt;

&lt;p&gt;이번에는 javax.validation 패키지의 @Max와 같이 값의 최대 크기를 제한하는 @IntMax 애너테이션을 정의해 보겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// IntMax.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IntMax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;MAX_VALUE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt;라는 이름의 하나의 요소를 가지고 있는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@IntMax&lt;/code&gt; 애너테이션입니다. 요소 이름 중 특별히 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt;의 경우에는 애너테이션을 사용할 때 요소 이름을 생략할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Point.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 생략하지 않고 표기&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@IntMax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// &quot;value =&quot; 부분을 생략할 수 있습니다.&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@IntMax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;하지만 애너테이션을 사용할 때 여러 개의 요소 값을 설정하는 경우에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt;를 생략할 수 없습니다.&lt;/p&gt;

&lt;p&gt;요소의 반환 타입이 배열인 경우는 요소에 값을 전달할 때 배열 리터럴을 사용하여 값을 전달할 수 있으며 예시는 아래와 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// AllowedValue.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AllowedValue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// AllowedValue 사용&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Radio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@AllowedValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;AM&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;FM&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 또는&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// @AllowedValue(value = { &quot;AM&quot;, &quot;FM&quot; })&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frequencyType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;요소의 반환 타입이 애너테이션인 경우는 아래와 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Book.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Author&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Author.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// AnnotationInAction.java&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@Author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nnoco&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnotationInAction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;애너테이션 타입의 요소에 값을 전달할 때는 애너테이션 표현식 그대로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@애너테이션(요소=값)&lt;/code&gt; 형태로 전달합니다.&lt;/p&gt;

&lt;h1 id=&quot;3-애너테이션-타입에-중첩-타입-정의&quot;&gt;3. 애너테이션 타입에 중첩 타입 정의&lt;/h1&gt;
&lt;p&gt;애너테이션 타입의 본문에는 해당 애너테이션 타입의 요소 외에도 중첩 타입(클래스, 인터페이스, 애너테이션, Enum 클래스)을 정의할 수 있습니다. 앞에서 다뤘던 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;level&lt;/code&gt; 요소는 반환 타입이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt;이고, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;level&lt;/code&gt; 요소의 값을 제한할 수 있는 방법이 없습니다. 이런 경우 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;level&lt;/code&gt; 요소의 반환 타입은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt; 보다 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enum&lt;/code&gt;을 사용하는 것이 적절해 보입니다.&lt;/p&gt;

&lt;p&gt;별도의 파일에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;level&lt;/code&gt;을 표현하기 위한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enum&lt;/code&gt;을 정의해도 되지만 해당 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enum&lt;/code&gt;은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 내에서만 사용되므로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log&lt;/code&gt; 애너테이션 내에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Level&lt;/code&gt; enum을 정의해 보겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Log.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Log&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 로그 레벨 - 기존 int 타입에서 Level 타입으로 변경&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Level&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// 로그 앞에 붙일 접두어&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// 반환 값도 로그로 출력할지 여부&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;logReturn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    
    &lt;span class=&quot;cm&quot;&gt;/* public 생략 */&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Level&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;DEBUG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;WARN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ERROR&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// LogTest.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LogTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DEBUG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logReturn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, Annotation!&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;애너테이션 타입인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Log&lt;/code&gt; 내에 중첩된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Level&lt;/code&gt;을 참고할 때는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Log.Level&lt;/code&gt;이 아닌 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Log.Level&lt;/code&gt;의 형식입니다. 애너테이션으로써 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Log&lt;/code&gt;를 참조하는 것이 아니라 타입으로써 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Log&lt;/code&gt;를 참조하기 때문입니다.&lt;/p&gt;

&lt;p&gt;enum 클래스 외에도 일반 클래스, 인터페이스, 애너테이션 역시 애너테이션 본문 내에 중첩해서 정의할 수 있으므로 상황에 맞게 정의하여 사용할 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;4-메타-애너테이션meta-annotation&quot;&gt;4. 메타 애너테이션(Meta Annotation)&lt;/h1&gt;
&lt;p&gt;애너테이션 타입의 속성을 설명하기 위한 애너테이션으로 메타 애너테이션이 있습니다. 이러한 메타 애너테이션으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Target&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Retention&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Inherited&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Documented&lt;/code&gt; 그리고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt;이 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;target-애너테이션&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Target&lt;/code&gt; 애너테이션&lt;/h2&gt;
&lt;p&gt;앞서 작성했던 애너테이션들은 소스 코드의 대부분에 태그하여 사용할 수 있었습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Target&lt;/code&gt; 애너테이션은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Target&lt;/code&gt; 애너테이션이 태그된 애너테이션을 어디에 태그할 것인지 제한할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// java.lang.annotation.Target&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;​&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Target&lt;/code&gt; 애너테이션은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ElementType&lt;/code&gt; enum 배열 타입의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; 요소가 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ElementType&lt;/code&gt;에는 아래와 같은 값이 정의되어 있습니다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TYPE&lt;/code&gt;: 타입(클래스, 인터페이스, 애너테이션, 열거형)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FIELD&lt;/code&gt;: 필드(멤버 변수) 선언, 열거형 선언도 포함됩니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;METHOD&lt;/code&gt;: 메서드&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PARAMETER&lt;/code&gt;: 메서드의 파라미터&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONSTRUCTOR&lt;/code&gt;: 생성자&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOCAL_VARIABLE&lt;/code&gt;: 지역 변수&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PACKAGE&lt;/code&gt;: package-info.java 파일의 패키지 선언&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TYPE_PARAMETER&lt;/code&gt;: 타입 파라미터(Java 8 이상)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TYPE_USE&lt;/code&gt;: 타입 파라미터를 포함한 타입 식별자(Java 8 이상)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MODULE&lt;/code&gt;: 모듈(Java 9 이상)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;예를 들어 생성자와 메서드에만 태그할 수 있는 애너테이션은 아래 코드와 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CONSTRUCTOR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;METHOD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OnlyConstructorAndMethod&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;retention-애너테이션&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Retention&lt;/code&gt; 애너테이션&lt;/h2&gt;
&lt;p&gt;애너테이션의 관점에서 애너테이션의 정보가 유지되는 단계를 나눠보면 소스 코드, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.class&lt;/code&gt; 파일(컴파일 타입), 런타임으로 나눠 볼 수 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Retention&lt;/code&gt; 애너테이션은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RetentionPolicy&lt;/code&gt; 열거형을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; 요소로 전달 받아 태그한 애너테이션의 정보를 어느 단계까지 유지할 지 설정할 수 있습니다.&lt;/p&gt;

&lt;p&gt;RetentionPolicy 열거형에 정의된 상수는 아래와 같습니다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOURCE&lt;/code&gt;: 소스 코드에서만 존재하며 컴파일 타임 및 런타임에는 애너테이션 정보가 유지되지 않습니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLASS&lt;/code&gt;: 소스 코드를 컴파일한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.class&lt;/code&gt; 파일까지만 유지됩니다. 런타임에는 애너테이션 정보가 유지되지 않습니다. 컴파일 타임에 애너테이션을 처리하는 경우 CLASS 상수를 사용합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Retention&lt;/code&gt; 애너테이션을 태그하지 않는 경우 기본 값입니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RUNTIME&lt;/code&gt;: 프로그램이 실행 중인 런타임에도 애너테이션 정보가 유지됩니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;애너테이션의 용도와 처리 시점에 따라 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Retention&lt;/code&gt;을 적용할 수 있습니다. 예를 들어 소스 코드의 최초 작성자를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Author&lt;/code&gt; 애너테이션을 정의해 기록하기로 했다면, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Author&lt;/code&gt; 애너테이션은 프로그램의 기능상으로 사용하지 않으므로 소스 코드에만 존재하면 됩니다. 이런 경우 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Author&lt;/code&gt; 애너테이션에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Retention(RetentionPolicy.SOURCE)&lt;/code&gt;을 태그하여 컴파일 타임이나 런타임에 불필요한 메모리를 차지하지 않도록 할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Author.java&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;SOURCE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 최초 작성자 이름&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// SourceExample.java&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nnoco&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SourceExample&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;만약 런타임에 애너테이션을 처리한다면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Retention(RetentionPolicy.RUNTIME)&lt;/code&gt;을 태그하여 런타임에도 애너테이션이 유지되도록 하여 처리할 수 있습니다. 런타임에 처리되어야 할 애너테이션의 Retention이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RetentionPolicy.RUNTIME&lt;/code&gt;으로 태그되어 있지 않다면 당연하게도 애너테이션 정보를 읽을 수 없습니다.&lt;/p&gt;

&lt;h2 id=&quot;inherited-애너테이션&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Inherited&lt;/code&gt; 애너테이션&lt;/h2&gt;
&lt;p&gt;애너테이션 정보는 기본적으로 하위 클래스로 상속되지 않습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Inherited&lt;/code&gt; 애너테이션은 애너테이션이 하위 클래스로 상속되도록 합니다. 애너테이션을 처리하는 과정에서 하위 클래스에서 애너테이션을 태그하지 않았다면, 해당 요소의 상위 클래스에서 애너테이션 정보를 찾습니다. 계층 구조를 가지고 있다면 가장 상위의 클래스에 도달할 때까지 반복됩니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// InheritedAnnotation.java&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Inherited&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Inherited&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;InheritedAnnotation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Inherited&lt;/code&gt; 애너테이션을 태그하여 하위 클래스에서도 애너테이션의 정보를 얻을 수 있도록 했고, 런타임에 처리하기 위해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Retention(RetentionPolicy.RUNTIME)&lt;/code&gt;을 태그해 주었습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// SuperClass.java&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@InheritedAnnotation&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SuperClass&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// SubClass.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SubClass&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SuperClass&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;printInheritedAnnotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;InheritedAnnotation&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;annotation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAnnotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;InheritedAnnotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;annotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@InheritedAnnotation&lt;/code&gt; 애너테이션을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SuperClass&lt;/code&gt;에 태그해주면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SuperClass&lt;/code&gt;를 상속한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubClass&lt;/code&gt;도 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@InheritedAnnotation&lt;/code&gt; 정보를 갖고 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubClass&lt;/code&gt;의 인스턴스를 생성하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printInheritedAnnotation()&lt;/code&gt; 메서드를 호출하면 “@com.nnoco.aia.ch2.InheritedAnnotation()”이 출력됩니다. (패키지 위치에 따라 달라질 수 있습니다.)&lt;/p&gt;

&lt;p&gt;만약 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Inherited&lt;/code&gt; 애너테이션이 없다면, 하위 클래스에서도 동일한 애너테이션을 태그해 주어야 합니다.&lt;/p&gt;

&lt;h2 id=&quot;documented-애너테이션&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Documented&lt;/code&gt; 애너테이션&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Documented&lt;/code&gt; 애너테이션을 태그하면 태그된 요소의 정보(public contract)에 태그된 애너테이션 정보가 포함됩니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Documented&lt;/code&gt;가 태그된 애너테이션을 태그하는 요소는 Javadoc이나 IDE에서 확인할 수 있게 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@InheritedAnnotation&lt;/code&gt;에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Documented&lt;/code&gt; 애너테이션을 태그하고 이를 확인해 보겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// InheritedAnnotation.java&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Documented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Inherited&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.lang.annotation.RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Inherited&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Documented&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;InheritedAnnotation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;IntelliJ IDEA 기준 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SuperClass&lt;/code&gt;에 커서를 두고 &lt;kbd&gt;F1&lt;/kbd&gt; 키를 누르면 Javadoc 주석을 확인할 수 있는데, 여기에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@InheritedAnnotation&lt;/code&gt;이 표시됩니다.&lt;/p&gt;

&lt;!-- https://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;
&lt;figure&gt;
    &lt;img src=&quot;/assets/images/2020/05-01_annotation/inherited1.png&quot; alt=&quot;@Documented가 태그된 @InheritedAnnotation이 Javadoc에 표시&quot; /&gt;
    &lt;figcaption&gt;@Documented가 태그된 @InheritedAnnotation이 Javadoc에 표시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;@InheritedAnnotation의 @Documented 부분을 주석처리하면 아래와 같이 @InheritedAnnotation이 표시되지 않습니다.&lt;/p&gt;

&lt;!-- https://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;
&lt;figure&gt;
    &lt;img src=&quot;/assets/images/2020/05-01_annotation/inherited2.png&quot; alt=&quot;@Documented가 태그되지 않은 경우 미표시&quot; /&gt;
    &lt;figcaption&gt;@Documented가 태그되지 않은 경우 미표시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;@InheritedAnnotation의 @Inherited와 상관없이 하위 클래스에서의 Javadoc에서는 표시되지 않습니다.&lt;/p&gt;

&lt;!-- https://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;
&lt;figure&gt;
    &lt;img src=&quot;/assets/images/2020/05-01_annotation/inherited3.png&quot; alt=&quot;SubClass에는 @InheritedAnnotation 미표시&quot; /&gt;
    &lt;figcaption&gt;SubClass에는 @InheritedAnnotation 미표시&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h1 id=&quot;repeatable-애너테이션&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt; 애너테이션&lt;/h1&gt;
&lt;p&gt;Java 8 이전에는 같은 애너테이션을 같은 요소에 여러 개 태그할 수 없었습니다. 아래 예시를 살펴보겠습니다.&lt;/p&gt;

&lt;p&gt;먼저 멤버 변수의 별칭을 애너테이션으로 정의하기 위해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Alias&lt;/code&gt; 애너테이션을 정의합니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Alias.java&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;그리고 아래 Person 클래스에서 name 멤버 변수에 두 개의 별칭을 지정하기 위해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Alias&lt;/code&gt; 애너테이션을 태그합니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Person.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;이름&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;성함&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Person 클래스를 컴파일 하면 컴파일 오류가 발생합니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Person.java:6: error: Alias is not a repeatable annotation type
    @Alias(&quot;성함&quot;)
    ^
1 error
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이를 해결하기 위해 여러 개의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Alias&lt;/code&gt; 애너테이션을 담을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Aliases&lt;/code&gt; 애너테이션을 정의해 줍니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Aliases&lt;/code&gt; 애너테이션과 같이 다른 애너테이션의 배열을 담은 애너테이션을 컨테이너(Container) 애너테이션이라고 합니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Aliases.java&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Aliases&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Person에 태그한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Alias&lt;/code&gt; 애너테이션은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Aliases&lt;/code&gt; 애너테이션으로 감싸서 아래와 같이 바꿔줄 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Person.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Aliases&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;@Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;이름&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;@Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;성함&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Java 8에서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt; 메타 애너테이션이 추가되어 애너테이션을 태그할 때는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Aliases&lt;/code&gt;로 감싸지 않고 여러 개의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Alias&lt;/code&gt;를 태그할 수 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Alias&lt;/code&gt; 애너테이션에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt; 애너테이션을 추가해 보겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Alias.java&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Retention&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RetentionPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RUNTIME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Repeatable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Aliases&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt;은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; 요소로 컨테이너 애너테이션의 클래스를 받습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt; 애너테이션이 추가되었지만 컨테이너 클래스는 필요합니다. 이 때 컨테이너 클래스에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt; 애너테이션이 태그된 애너테이션 배열 타입의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; 이름을 갖는 요소가 정의되어 있어야 합니다. 이름이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt;가 아니거나, 타입이 일치하지 않는 경우 컴파일 오류가 발생합니다.&lt;/p&gt;

&lt;p&gt;앞서 작성한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Aliases&lt;/code&gt; 컨테이너 애너테이션은 이미 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alias[]&lt;/code&gt; 타입의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; 요소가 정의되어 있으므로 그대로 사용할 수 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Alias&lt;/code&gt; 애너테이션에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable(Aliases.class)&lt;/code&gt;를 태그했으므로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Person.java&lt;/code&gt; 파일은 다시 아래와 같이 작성할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Person.java&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;이름&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;성함&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;여러 개의 동일한 애너테이션을 태그한 경우 리플렉션에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAnnotationsByType(Class&amp;lt;? extends Annotation&amp;gt;)&lt;/code&gt; 메서드에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt;이 태그된 애너테이션 클래스를 전달하여 배열로 가져오거나, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAnnotation(Class&amp;lt;? extends Annotation&amp;gt;)&lt;/code&gt; 메서드에 컨테이너 애너테이션의 클래스를 전달하여 컨테이너를 가져와 컨테이너에 포함된 애너테이션을 가져올 수 있습니다.&lt;/p&gt;

&lt;p&gt;아래는 리플렉션을 통해 런타임에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Person&lt;/code&gt; 클래스의 멤버 변수에 태그된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alias&lt;/code&gt; 애너테이션을 가져오는 예시입니다. 리플렉션을 통한 애너테이션 처리는 다음 글에서 상세히 다루도록 하고, 여기에서는 간략하게 설명하겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AliasProcessor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 컨테이너 애너테이션으로 가져오기&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Aliases&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getByContainer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fieldName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NoSuchFieldException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Field&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDeclaredField&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAnnotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Aliases&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// @Repeatable이 적용된 애너테이션으로 가져오기&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getByItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fieldName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NoSuchFieldException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Field&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDeclaredField&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAnnotationsByType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getByItem2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fieldName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NoSuchFieldException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Field&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDeclaredField&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAnnotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NoSuchFieldException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;AliasProcessor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AliasProcessor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;Aliases&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aliases&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getByContainer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;alias:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aliases&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Aliases: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aliasArray&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getByItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;alias:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aliasArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;AliasArray: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 아래는 null을 반환&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Alias&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getByItem2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;// NullPointerException 발생&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt; 클래스에는 클래스의 모든 정보를 포함하고 있습니다. 클래스의 필드(멤버 변수)를 가져오기 위해서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getDeclaredField(String)&lt;/code&gt;메서드에 필드의 이름을 전달하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field&lt;/code&gt; 객체를 가져옵니다. 그리고 해당 필드에 태그된 애너테이션을 가져오기 위해서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAnnotation(Class)&lt;/code&gt; 또는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAnnotationsByType(Class)&lt;/code&gt; 메서드를 사용합니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAnnotation(Class)&lt;/code&gt; 메서드는 Java 5에서 추가된 메서드로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt;을 지원하지 않습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAnnotation(Class)&lt;/code&gt; 메서드를 사용할 때는 컨테이너 클래스를 전달하여 컨테이너 클래스를 반환 받은 후 그 안의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; 요소에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alias&lt;/code&gt; 배열을 얻을 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAnnotationsByType(Class)&lt;/code&gt; 메서드는 Java 8에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt;과 함께 추가된 메서드로써 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Alias&lt;/code&gt; 애너테이션의 클래스를 전달하면 컨테이너 없이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alias&lt;/code&gt; 배열을 가져올 수 있습니다.&lt;/p&gt;

&lt;p&gt;애너테이션을 정의하고 태그하여 사용하는 것은 프로그램의 기능에 아무런 영향을 주지 않지만 리플렉션이나 애너테이션 처리 API를 활용하면 실제로 애너테이션을 이용해 동작하는 프로그램을 작성할 수 있습니다. 이 후의 글에서는 작성한 애너테이션을 어떻게 처리할 수 있는지에 대해 다뤄보도록 하겠습니다.&lt;/p&gt;

&lt;hr /&gt;
&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;https://docs.oracle.com/javase/specs/jls/se8/html&lt;/li&gt;
&lt;/ul&gt;</content><author><name>nnoco</name></author><category term="Java" /><category term="Annotation" /><category term="APT" /><category term="PAPA" /><category term="Reflection" /><summary type="html">1편에서 소개한 애너테이션은 필요에 따라 직접 정의하여 활용할 수 있습니다. 이러한 애너테이션을 사용자 정의(User Defined) 또는 커스텀(Custom) 애너테이션이라고 합니다. 애너테이션도 인터페이스, 클래스와 같은 하나의 타입이며, 인터페이스의 특성을 갖습니다. 이번 글에서는 애너테이션을 작성하기 위한 문법과 애너테이션의 특성을 부여하기 위한 자바 내장 애너테이션에 대해 다뤄보겠습니다.</summary></entry><entry><title type="html">Java Annotation in Action 1</title><link href="https://nnoco.github.io/dev/java/2020/05/01/Java-Annotation-in-Action-1.html" rel="alternate" type="text/html" title="Java Annotation in Action 1" /><published>2020-05-01T19:35:44+09:00</published><updated>2020-05-01T19:35:44+09:00</updated><id>https://nnoco.github.io/dev/java/2020/05/01/Java-Annotation-in-Action-1</id><content type="html" xml:base="https://nnoco.github.io/dev/java/2020/05/01/Java-Annotation-in-Action-1.html">&lt;p&gt;자바 5(J2SE 5) 버전 이상부터 애너테이션(Annotation) 기능을 사용할 수 있습니다. 자바의  애너테이션은 소스코드의 클래스, 메서드, 멤버 변수나 주석에 붙여 메타 데이터를 제공할 수 있습니다. 메타 데이터란 데이터의 데이터를 의미합니다. 조금 말장난 같지만 주 데이터에 필요하거나 설명하기 위한 부가적인 데이터로 볼 수 있습니다. 현실에서의 예를 들어보면 여러 전원 케이블을 구분하기 위해 케이블에 꼬리표를 붙여 냉장고의 전원 케이블인지 텔레비전의 케이블인지, 스탠드 조명의 케이블인지 구분할 수 있습니다. 이 경우 꼬리표가 전원 케이블의 메타 데이터입니다. 또한 도서의 저자, 출판사, ISDN 등의 데이터도 메타 데이터입니다.&lt;/p&gt;

&lt;h1 id=&quot;1-자바-애너테이션&quot;&gt;1. 자바 애너테이션&lt;/h1&gt;
&lt;p&gt;자바의 애너테이션은 “@애너테이션 이름”의 형태로 소스코드에 태그하여 메타데이터를 표현할 수 있습니다. 간단한 예시로 자바에 내장되어 있는 애너테이션으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Override&lt;/code&gt;를 살펴보겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;위 예시에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Override&lt;/code&gt; 애너테이션은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toString&lt;/code&gt; 메서드에 태그되어 “toString 메서드는 상위 클래스의 toString 메서드를 오버라이드 했다”는 데이터를 추가할 수 있습니다. 자바의 메서드 자체는 오버라이드 여부를 표현할 수 없지만 애너테이션으로 “오버라이드 메서드”라는 데이터를 추가해 줄 수 있습니다. 이렇게 추가된 @Override 애너테이션은 컴파일러에서도 활용할 수 있고, 주석을 굳이 작성하지 않아도 애너테이션만으로 사람도 코드를 읽을 때 오버라이드 메서드인 것을 알 수 있게 됩니다.&lt;/p&gt;

&lt;p&gt;애너테이션 자체는 데이터로써만 존재할 뿐 어떠한 기능을 갖는 것은 아닙니다. 자바의 리플렉션(Reflection) API나 PAPA(Pluggable Annotation Processing API)를 활용해서 컴파일 타임이나 런타임에 소스코드에 태그된 애너테이션 정보를 읽어 처리할 수 있게 합니다.&lt;/p&gt;

&lt;h1 id=&quot;2-자바-내장-애너테이션&quot;&gt;2. 자바 내장 애너테이션&lt;/h1&gt;
&lt;p&gt;자바 표준 API에 정의된 애너테이션으로는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Override&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Deprecated&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SuprpressWarning&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SafeVaragrs&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@FunctionalInterface&lt;/code&gt; 그리고 애너테이션 타입에 태그하는 애너테이션인 메타 애너테이션으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Target&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Retention&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Inherited&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Documented&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Repeatable&lt;/code&gt;이 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;override&quot;&gt;@Override&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Override&lt;/code&gt; 애너테이션은 앞서 간단히 설명했듯 @Override 애너테이션을 태그한 메서드가 부모 클래스로부터 상속 받은 메서드를 재정의(Override) 함을 의미합니다.&lt;/p&gt;

&lt;h2 id=&quot;deprecated&quot;&gt;@Deprecated&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Deprecated&lt;/code&gt; 애너테이션은 생성자, 필드, 지역변수, 메서드, 파라미터, 타입(클래스, 인터페이스 등) 등에 태그할 수 있고, 태그된 요소의 사용을 더 이상 권장하지 않는 경우에 사용합니다. 이를테면 메서드가 더 이상 유지보수 되지 않고, 다음 버전에서 제거되는 경우 상위 버전 호환을 위하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Deprecated&lt;/code&gt; 애너테이션을 태그하여 메서드를 사용하는 개발자에게 알립니다. 이런 경우 대개 Javadoc 주석으로 대체할 방법을 안내합니다. 직접 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Deprecated&lt;/code&gt;를 사용하는 경우에도 Deprecated의 이유와 대체 방법 등을 Javadoc 주석으로 안내하는 것이 좋습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DeprecatedExample&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/**
     * @deprecated 더 이상 {@link DeprecatedExample#a} 메서드는 유지보수 되지 않습니다.
     * {@link DeprecatedExample#b} 를 사용해 주십시오.
     */&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Deprecated&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a()&lt;/code&gt; 메서드에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Deprecated&lt;/code&gt; 애너테이션과 함께 Javadoc 주석을 활용하여 설명을 적어주면, Javadoc 문서 생성 시 해당 내용이 출력되고, 대부분의 IDE에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a()&lt;/code&gt; 메서드 참조 시 Deprecated 된 것을 표시해 줍니다. 아래는 IntelliJ IDEA의 예시입니다.&lt;/p&gt;

&lt;!-- https://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;
&lt;figure&gt;
    &lt;img src=&quot;/assets/images/2020/05-01_annotation/intellij_deprecated.png&quot; alt=&quot;IntelliJ IDEA - a() 메서드 호출 시 취소선으로 표시&quot; /&gt;
    &lt;figcaption&gt;IntelliJ IDEA - a() 메서드 호출 시 취소선으로 표시&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!-- https://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;
&lt;figure&gt;
    &lt;img src=&quot;/assets/images/2020/05-01_annotation/intellij_javadoc.png&quot; alt=&quot;a() 메서드의 Javadoc&quot; /&gt;
    &lt;figcaption&gt;a() 메서드의 Javadoc&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Java 9 에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Deprecated&lt;/code&gt; 애너테이션에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;since&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forRemoval&lt;/code&gt; 요소가 추가되어 보다 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Deprecated&lt;/code&gt; 애너테이션에 추가적인 정보를 전달할 수 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;since&lt;/code&gt;는 Deprecated 되는 버전 문자열, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forRemoval&lt;/code&gt;은 Deprecated의 사유가 삭제인지 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;로 전달합니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// java.lang 패키지의 Runtime 클래스 내 transactionInstructions(boolean) 메서드&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/**
 * Not implemented, does nothing.
 *
 * @deprecated
 * This method was intended to control instruction tracing.
 * It has been superseded by JVM-specific tracing mechanisms.
 * This method is subject to removal in a future version of Java SE.
 *
 * @param on ignored
 */&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Deprecated&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;9&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forRemoval&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;traceInstructions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;자바 내장 타입인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Runtime&lt;/code&gt; 클래스의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traceInstructions(boolean)&lt;/code&gt; 메서드에 태그된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Deprecated&lt;/code&gt; 애너테이션입니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;since&lt;/code&gt; 요소에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;9&quot;&lt;/code&gt;,  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forRemoval&lt;/code&gt;이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;인 것으로 미루어 Java 9 버전부터 Deprecated 되었고, 이 후 삭제될 수 있음을 알 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;suppresswarnings&quot;&gt;@SuppressWarnings&lt;/h2&gt;
&lt;p&gt;자바 컴파일러는 정적 분석을 통해 잘못된 코드, 비효율적인 코드, 혹은 오류가 발생할 수 있는 가능성이 있는 코드를 탐지할 수 있고, 컴파일 시 옵션으로 -Xlint를 추가하면 경고 메시지를 출력해 줍니다. IDE는 소스코드 편집기에서 같은 내용을 강조하여 보여주기도 합니다.&lt;/p&gt;

&lt;p&gt;아래는 제너릭 리스트를 타입 파라미터 없이 사용하고 있는 코드입니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// SuppressWarningsExample.java &lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.ArrayList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SuppressWarningsExample&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    	&lt;span class=&quot;c1&quot;&gt;// 파라미터화된 타입을 사용하지 않고 List 사용&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ArrayList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;위의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Test.java&lt;/code&gt; 파일을 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javac -Xlint SuppressWarningsExample.java&lt;/code&gt; 명령으로 컴파일하면 아래와 같은 메시지가 출력됩니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;javac &lt;span class=&quot;nt&quot;&gt;-Xlint&lt;/span&gt; SuppressWarningsExample.java
SuppressWarningsExample.java:6: warning: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;rawtypes] found raw &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;: List
        List list &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; new ArrayList&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        ^
  missing &lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;arguments &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;generic class List
  where E is a type-variable:
    E extends Object declared &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;interface List
SuppressWarningsExample.java:6: warning: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;rawtypes] found raw &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;: ArrayList
        List list &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; new ArrayList&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                        ^
  missing &lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;arguments &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;generic class ArrayList
  where E is a type-variable:
    E extends Object declared &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;class ArrayList
2 warnings
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;rawtypes는 타입 파라미터가 정의되었을 때 파라미터화된 타입을 전달하지 않았을 때를 일컫습니다. 만약 이러한 코드에서 의도적으로 타입 파라미터를 전달하지 않았다면 경고 메시지는 방해가 될 수 있습니다. 이럴 때 컴파일러의 경고 메시지를 출력하지 않도록 할 때 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SuppressWarnings&lt;/code&gt; 애너테이션을 사용할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.ArrayList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SuppressWarningsExample&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    	&lt;span class=&quot;c1&quot;&gt;// @SuppressWarnings 애너테이션을 태그하여 컴파일 경고 무시&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;@SuppressWarnings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;rawtypes&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ArrayList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;위와 같이 경고가 발생하는 코드에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SuppressWarnings&lt;/code&gt; 애너테이션을 태그한 후 컴파일하면 경고 메시지가 출력되지 않는 것을 확인할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SuppressWarnings&lt;/code&gt; 애너테이션은 어떤 타입의 경고를 무시할 지 value 요소에 단일 값 또는 배열로 전달할 수 있고, 위에서는  컴파일 시 출력된 경고 메시지의 “SuppressWarningsExample.java:6: warning: [rawtypes] found raw type: List” 에서 표시된 rawtypes를 무시하도록 했습니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SuppressWarnings&lt;/code&gt;에 전달할 수 있는 경고 타입은 아래와 같습니다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;auxiliaryclass: Warn about an auxiliary class that is hidden in a source file, and is used from other files.&lt;/li&gt;
  &lt;li&gt;cast: 불필요한 타입 캐스팅을 하는 경우&lt;/li&gt;
  &lt;li&gt;classfile: classfile 컨텐츠에 관련된 이슈가 있는 경우&lt;/li&gt;
  &lt;li&gt;deprecation: deprecated 항목을 사용하는 경우&lt;/li&gt;
  &lt;li&gt;dep-ann: Javadoc 주석에 deprecated를 표시하고 있지만 @Deprecated 애너테이션을 태그하지 않은 경우&lt;/li&gt;
  &lt;li&gt;divzero: 0으로 나누는 경우&lt;/li&gt;
  &lt;li&gt;empty: if 구분의 내용이 비어있는 경우&lt;/li&gt;
  &lt;li&gt;exports: 모듈 Export에 대한 이슈가 있는 경우&lt;/li&gt;
  &lt;li&gt;fallthrough: switch 구문에서 break 하지 않고 다음 case로 넘어가는(Fall through) 경우&lt;/li&gt;
  &lt;li&gt;finally: 정상적으로 종료되지 않는 finally 절이 있는 경우&lt;/li&gt;
  &lt;li&gt;module: 모듈 시스템과 관련된 이슈가 있는 경우&lt;/li&gt;
  &lt;li&gt;opens: 모듈 오픈에 관련된 이슈가 있는 경우&lt;/li&gt;
  &lt;li&gt;options: 커맨드 라인 옵션 사용과 관련된 문제가 있는 경우&lt;/li&gt;
  &lt;li&gt;overloads: 잘못된 오버로드와 관련된 문제가 있는 경우&lt;/li&gt;
  &lt;li&gt;overrides: 잘못된 오버라이드와 관련된 문제가 있는 경우&lt;/li&gt;
  &lt;li&gt;path: 커맨드 라인의 잘못된 경로 요소가 있는 경우&lt;/li&gt;
  &lt;li&gt;processing: 애너테이션 프로세싱과 관련된 문제가 있는 경우&lt;/li&gt;
  &lt;li&gt;rawtypes: 타입 파라미터가 정의되어 있지만 사용하지 않는 경우&lt;/li&gt;
  &lt;li&gt;removal: 삭제될 예정인 API를 사용하는 경우&lt;/li&gt;
  &lt;li&gt;requires-automatic: requires 절에서 자동 모듈을 사용하는 경우&lt;/li&gt;
  &lt;li&gt;requires-transitive-automatic:  requires transitive 에서 자동 모듈을 사용하는 경우&lt;/li&gt;
  &lt;li&gt;serial: Serializable 인터페이스를 구현한 클래스에서 Serial Version ID를 정의하지 않거나, public이 아닌 경우&lt;/li&gt;
  &lt;li&gt;static: 인터페이스에서 static 멤버를 액세스하는 경우&lt;/li&gt;
  &lt;li&gt;try: try 블록 사용과 관련된 문제가 있는 경우&lt;/li&gt;
  &lt;li&gt;unchecked: (타입 체크 등의) 체크를 수행하지 않은 연산의 경우 - 예) 타입 체크를 하지 않고 타입 캐스팅&lt;/li&gt;
  &lt;li&gt;varargs: 잠재적으로 안전하지 않은 가변 인자를 가진 메서드에 관한 문제가 있는 경우&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이러한 경고들은 컴파일은 수행할 수 있지만 런타임에 잠재적으로 문제를 가진 것들입니다. 따라서 경고를 없애기 위해 @SuppressWarnings 애너테이션을 무분별하게 사용하기보다, 경고를 없앨 수 있는 방법을 찾아보고, 해당 코드가 의도적으로 경고가 발생할 수 있도록 작성되었으며, 런타임에도 오류가 발생하지 않는 것이 분명할 때만 사용하는 것이 좋을 것입니다.&lt;/p&gt;

&lt;h2 id=&quot;safevarargs&quot;&gt;@SafeVarargs&lt;/h2&gt;
&lt;p&gt;메서드나 생성자에 에 가변인자(Varargs, Vargs, Variable Arguments)를 사용하면 메서드를 유연하게 사용할 수 있지만, 제너릭 가변인자를 사용하는 경우 타입 안전성이 깨질 수 있습니다. 또한 자바 언어 명세(Java Language Specification, JLS) 4.12.2에서는 파라미터화된 타입의 변수가 다른 타입의 객체를 참조하는, 힙 오염(Heap Pollution)이 발생한다고 안내하고 있습니다. (Joshua Bloch - Effective Java 3/E, Item 32에서 제너릭 가변인자의 문제점과 안전한 제너릭 가변인자를 사용하기 위한 내용을 설명하고 있습니다.)&lt;/p&gt;

&lt;p&gt;아래 코드는 컴파일하면 unchecked 타입의 경고를 출력합니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// SafeVargsExample.java&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SafeVargsExample&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;SafeVargsExample.java:2: warning: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;unchecked] Possible heap pollution from parameterized vararg &lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;T
    static  void foo&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;T... args&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                             ^
  where T is a type-variable:
    T extends Object declared &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;method toArray&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;T...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
1 warning
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 경고는 마찬가지로 런타임에 오류를 발생시킬 수 있기 때문에 출력되지만, 앞서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SuppressWarnings&lt;/code&gt;와 마찬가지로 코드에서 오류가 발생하지 않는 것이 분명한 경우 경고를 무시하도록 할 수 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SuppressWarnings(&quot;unchecked&quot;)&lt;/code&gt; 는 위의 경고를 무시하도록 합니다. 하지만 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SuppressWarnings(&quot;unchecked&quot;)&lt;/code&gt;의 경우 태그한 요소의 하위 요소의 동일 타입(unchecked)의 경고를 무시하게 되므로 어떤 이유로 인해 오류를 무시하도록 한 것인지 의도를 파악하기 어렵습니다. 자바 7 버전 이 전에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SuppressWarnings(&quot;unchecked&quot;)&lt;/code&gt;를 사용했지만 자바 1.7 에는 한정적으로 제너릭 가변인자에 대한 경고를 무시하도록 하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@SafeVarargs&lt;/code&gt; 애너테이션이 추가되었습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// SafeVarargsExample&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SafeVarargsExample&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// foo 메서드에 @SafeVarargs 추가&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@SafeVarargs&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;foo 메서드에 @SafeVarargs를 태그하면 컴파일 시 경고가 발생하지 않습니다.&lt;/p&gt;

&lt;h2 id=&quot;functionalinterface&quot;&gt;@FunctionalInterface&lt;/h2&gt;
&lt;p&gt;Java 8에서는 함수형 프로그래밍을 위한 많은 문법과 API가 추가되었습니다. 함수형 인터페이스(Functional Interface)는 하나의 추상 메서드만을 가지는 인터페이스를 의미하며, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@FunctionalInterface&lt;/code&gt; 애너테이션을 인터페이스에 태그하면 해당 인터페이스가 하나의 추상 메서드만 가지도록 강제합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@FunctionalInterface&lt;/code&gt; 애너테이션을 태그한 인터페이스가 2개 이상의 추상 메서드를 가진다면 컴파일 오류가 발생합니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// FunctionalInterfaceExample.java&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@FunctionalInterface&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FunctionalInterfaceExample&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;컴파일 결과&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;FunctionalInterfaceExample.java:2: error: Unexpected @FunctionalInterface annotation
@FunctionalInterface
^
  FunctionalInterfaceExample is not a functional interface
    multiple non-overriding abstract methods found &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;interface FunctionalInterfaceExample
1 error
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@FunctionalInterface&lt;/code&gt; 애너테이션을 태그하지 않았다면, 다른 개발자가 원래 개발자가 작성한 코드의 의도를 파악하지 못하고 실수로 메서드를 추가할 수도 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@FunctionalInterface&lt;/code&gt;는 이러한 일이 발생하는 것을 방지해주는 역할을 합니다.&lt;/p&gt;

&lt;h1 id=&quot;3-애너테이션-활용의-예시&quot;&gt;3. 애너테이션 활용의 예시&lt;/h1&gt;
&lt;p&gt;애너테이션을 활용하면 반복되는 보일러 플레이트 코드의 작성을 줄일 수도 있고, 메서드가 호출될 때 부가적인 기능을 수행하게끔 만들 수도 있습니다. 많은 라이브러리나 프레임워크에서는 애너테이션을 활용하고 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;lombok&quot;&gt;Lombok&lt;/h2&gt;
&lt;p&gt;Lombok은 클래스의 Getter, Setter, 생성자 등의 코드를 컴파일 타임에 자동으로 생성해 주는 라이브러리입니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;lombok.AllArgsConstructor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;lombok.Getter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;lombok.NoArgsConstructor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;lombok.Setter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Getter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;nd&quot;&gt;@Setter&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Getter&lt;/code&gt;나 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Setter&lt;/code&gt; 메서드는 멤버 변수의 Setter와 Getter를 생성해주고, 클래스 레벨에서 태그하거나, 개별 멤버 변수에 태그할 수 있습니다. 위의 코드에서는 클래스 레벨에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Getter&lt;/code&gt;를, price 멤버 변수에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Setter&lt;/code&gt;를 태그해서 title, price 멤버 변수의 Getter와 price 멤버 변수의 Setter를 자동으로 생성합니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NoArgsConstructor&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@AllArgsConstructor&lt;/code&gt;는 생성자를 생성하도록 하는 애너테이션이며 이름대로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@NoArgsConstructor&lt;/code&gt;는 인자가 없는 생성자, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@AllArgsConstructor&lt;/code&gt;는 모든 멤버 변수를 초기화하기 위한 인자를 받아 초기화하는 생성자를 생성합니다. 위 Lombok 애너테이션을 적용해서 생성된 결과는 아래와 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getTitle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getPrice&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setPrice&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;spring-framework&quot;&gt;Spring Framework&lt;/h2&gt;
&lt;p&gt;Spring Framework는 XML을 통해 할 수 있었던 애플리케이션 설정, 빈 생성 등의 작업을 애너테이션을 이용해 자바 코드에서도 할 수 있도록 지원합니다. 또한 Spring Web에서는 컨트롤러 클래스의 핸들러 메서드 매핑을 애너테이션으로 선언적으로 설정할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.springframework.web.bind.annotation.*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@RestController&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@RequestMapping&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/api/books&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BookApiController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@GetMapping&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBooks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;nd&quot;&gt;@GetMapping&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/{id}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBook&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@PathVariable&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BookApiController&lt;/code&gt; 클래스를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@RestController&lt;/code&gt; 애너테이션으로 스프링의 컨트롤러 빈으로 등록하고, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@XxxMapping&lt;/code&gt; 애너테이션들을 이용해 어떤 요청 경로에 매핑할 것인지 설정합니다. 클래스에 태그된 애너테이션들을 읽어 애플리케이션으로 들어오는 요청을 자동으로 처리할 수 있게 됩니다.&lt;/p&gt;

&lt;h2 id=&quot;bean-validation&quot;&gt;Bean Validation&lt;/h2&gt;
&lt;p&gt;Java EE(Enterprise Edition) 6 이상에서 빈의 유효성 검증을 위한 클래스들이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javax.validation&lt;/code&gt; 패키지에 정의되어 있으며, 폼(Form) 요청 등의 데이터를 검증하기 위해 애너테이션을 활용할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;javax.validation.constraints.Min&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;javax.validation.constraints.NotEmpty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;javax.validation.constraints.Size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;title은 100자를 초과할 수 없습니다.&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@NotEmpty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;title은 필수 입력 항목입니다.&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Min&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;가격은 음수일 수 없습니다.&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;길이 제한, Null 가능 여부, Empty 가능 여부, 최대/최소값, 정규표현식을 통한 패턴 체크 등의 유효성 설정을 애너테이션으로 태그하고, 유효성 검사기(Validator)로 객체에 담긴 값이 유효한지 확인할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;feign&quot;&gt;Feign&lt;/h2&gt;
&lt;p&gt;Feign은 애너테이션 기반의 HTTP Client 라이브러리입니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;feign.Param&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;feign.RequestLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BookApiClient&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@RequestLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;GET /api/books&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBooks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@RequestLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Get /api/books/{id}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBook&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@Param&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;HTTP 요청을 위한 정보를 담고 있는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BookApiClient&lt;/code&gt; 인터페이스를 작성합니다. HTTP 요청을 “어떻게” 해야하는지는 명시할 필요가 없고 “무엇을” 요청해야하는지만 애너테이션으로 정의해 주면됩니다.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;feign.Feign&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BookApiClientTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;BookApiClient&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Feign&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BookApiClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;http://some.where...&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;books&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBooks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;book&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBook&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1L&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;그리고 Feign 클래스를 통해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BookApiClient&lt;/code&gt;가 실제로 동작할 수 있도록 객체를 생성해서 별다른 HTTP 통신 관련 코드를 작성하지 않아도 인터페이스에서 정의한 메서드를 사용해서 API를 호출할 수 있습니다.&lt;/p&gt;

&lt;p&gt;위의 예시에서 살펴본 것과 같이 애너테이션은 선언적 프로그래밍을 가능하게 해주고 반복적인 많은 코드를 작성하는 수고를 덜 수 있게 도와줄 수 있습니다. 물론 런타임에 애너테이션을 읽어 처리할 때는 그만큼 실행 속도가 느려지는 등의 단점은 있습니다.&lt;/p&gt;

&lt;p&gt;이 후의 글에서는 직접 애너테이션을 작성하고 처리하는 방법, 속도 이슈를 해결하기 위한 방법을 다뤄보도록 하겠습니다.&lt;/p&gt;</content><author><name>nnoco</name></author><category term="Java" /><category term="Annotation" /><category term="APT" /><category term="PAPA" /><category term="Reflection" /><summary type="html">자바 5(J2SE 5) 버전 이상부터 애너테이션(Annotation) 기능을 사용할 수 있습니다. 자바의 애너테이션은 소스코드의 클래스, 메서드, 멤버 변수나 주석에 붙여 메타 데이터를 제공할 수 있습니다. 메타 데이터란 데이터의 데이터를 의미합니다. 조금 말장난 같지만 주 데이터에 필요하거나 설명하기 위한 부가적인 데이터로 볼 수 있습니다. 현실에서의 예를 들어보면 여러 전원 케이블을 구분하기 위해 케이블에 꼬리표를 붙여 냉장고의 전원 케이블인지 텔레비전의 케이블인지, 스탠드 조명의 케이블인지 구분할 수 있습니다. 이 경우 꼬리표가 전원 케이블의 메타 데이터입니다. 또한 도서의 저자, 출판사, ISDN 등의 데이터도 메타 데이터입니다.</summary></entry><entry><title type="html">문자 인코딩, 문자셋, 유니코드</title><link href="https://nnoco.github.io/study/gardenist/2020/05/01/%EB%AC%B8%EC%9E%90-%EC%9D%B8%EC%BD%94%EB%94%A9,-%EB%AC%B8%EC%9E%90%EC%85%8B,-%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C.html" rel="alternate" type="text/html" title="문자 인코딩, 문자셋, 유니코드" /><published>2020-05-01T13:49:19+09:00</published><updated>2020-05-01T13:49:19+09:00</updated><id>https://nnoco.github.io/study/gardenist/2020/05/01/%EB%AC%B8%EC%9E%90-%EC%9D%B8%EC%BD%94%EB%94%A9,-%EB%AC%B8%EC%9E%90%EC%85%8B,-%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C</id><content type="html" xml:base="https://nnoco.github.io/study/gardenist/2020/05/01/%EB%AC%B8%EC%9E%90-%EC%9D%B8%EC%BD%94%EB%94%A9,-%EB%AC%B8%EC%9E%90%EC%85%8B,-%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C.html">&lt;p&gt;컴퓨터는 결국 0과 1로 표현됩니다. 우리가 컴퓨터를 사용하면서 보는 글자, 이미지, 파일 등도 어떤 방식으로든 0과 1로 저장이되거나 전송이 됩니다. 그래서 0과 1로 변환하는 것을 인코딩(Encoding, 부호화)이라고 하며, 이 중 글자를 0과 1로 변환하는 것을 문자 인코딩(Character Encoding)이라고 합니다.&lt;/p&gt;

&lt;h1 id=&quot;문자-인코딩과-문자-셋&quot;&gt;문자 인코딩과 문자 셋&lt;/h1&gt;
&lt;p&gt;위키피디아의 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%B6%80%ED%98%B8%ED%99%94&quot;&gt;부호화&lt;/a&gt; 문서에는 아래와 같이 정의되어 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;부호화 또는 인코딩(encoding)은 정보의 형태나 형식을 표준화, 보안, 처리 속도 향상, 저장 공간 절약 등을 위해서 다른 형태나 형식으로 변환하는 처리 혹은 그 처리 방식을 말한다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;문자 부호화에 맞게 각색해서 다시 정의해보면 “문자 부호화 또는 문자 인코딩은 문자를 저장하거나 처리하기 위한 변환 혹은 그 변환 방법을 말한다.”로 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;컴퓨터에 맞게 한글 인코딩 방법을 아주 간단한 예를 들어보면 이와 같이 정의해볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;“2개의 byte를 사용해 자음 ㄱ은 0x0000, ㄴ은 0x0001, ㄷ은 0x0002 와 같이 변환한다.”&lt;/p&gt;

&lt;p&gt;인코딩의 반대는 디코딩(복호화)이라고 하며, 위의 정의에서 우리는 0x0000을 디코딩하면 ㄱ이 되는 것을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;문자 셋(문자 집합, Character set, Charset)은 문자들의 집합을 정의한 것으로 문자 셋에서 다루는 문자에 음수가 아닌 정수들을 배정한 것을 부호화된 문자 셋(coded character set, CCS)라고 합니다. ASCII, EUC-KR, UTF-8 등 대개의 문자 셋들은 부호화된 문자 셋에 해당하며, 일반적으로 문자 집합과 문자 인코딩은 어떤 문자를 사용할 수 있으며 어떤 식으로 표현되는지를 나타낸다는 점에서 동의어로 취급되기도 합니다. (&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%AC%B8%EC%9E%90_%EC%9D%B8%EC%BD%94%EB%94%A9&quot;&gt;위키피디아 문자 인코딩&lt;/a&gt;)&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;유니코드&quot;&gt;유니코드&lt;/h1&gt;

&lt;p&gt;컴퓨터가 개발된 초기에는 여러 나라의 문자를 다룰 필요성이 크지 않았지만(ASCII만 해도 1963년에 표준화 초판이 발간되었음) 점차 표준화된 다국어 표현을 위해 유니코드가 개발되었습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;유니코드(Unicode)는 전 세계의 모든 문자를 컴퓨터에서 일관되게 표현하고 다룰 수 있도록 설계된 산업 표준이며, 유니코드 협회(Unicode Consortium)가 제정한다.&lt;br /&gt;
(중략)
유니코드의 목적은 현존하는 문자 인코딩 방법들을 모두 유니코드로 교체하려는 것이다. 기존의 인코딩들은 그 규모나 범위 면에서 한정되어 있고, 다국어 환경에서는 서로 호환되지 않는 문제점이 있었다. 유니코드가 다양한 문자 집합들을 통합하는 데 성공하면서 유니코드는 컴퓨터 소프트웨어의 국제화와 지역화에 널리 사용되게 되었으며, …&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C&quot;&gt;위키피디아 유니코드&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;이러한 유니코드는 1988년에 초안이 발간되어 1991년 10월에 한글이 포함되었습니다. 이후 1996년 7월 2.0 버전에 11,172자의 새 한글 완성자 영역을 새로 지정하였습니다.&lt;/p&gt;

&lt;p&gt;유니코드는 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%ED%8F%89%EB%A9%B4&quot;&gt;유니코드 평면&lt;/a&gt;이라는 유니코드 전체를 논리적으로 나눈 범위를 정의하고 있으며, 0번에서 16번까지 모두 17개의 유니코드 평면으로 나뉘며, 각 평면은 65536개(2의 16제곱)의 코드로 구성됩니다.&lt;/p&gt;

&lt;p&gt;그 중 첫 번째인 0번 평면은 다국어 기본 평면(Basic multilingual plane, BMP)으로 U+0000부터 U+FFFF까지의 영역을 차지합니다. 다국어 기본 평면에는 거의 모든 근대 문자와 특수 문자가 포함되어 있으며, 그 중 대부분은 한글과 한중일 통합 한자들로 이루어져 있습니다.&lt;/p&gt;

&lt;p&gt;&amp;lt;위키피디아 - 다국어 기본 평면&amp;gt; - 한 칸은 문자 256개를 나타냅니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://s3-us-west-2.amazonaws.com/secure.notion-static.com/49dc6b8b-e6ea-4bd3-af6e-e622c55909b7/Untitled.png&quot; alt=&quot;https://s3-us-west-2.amazonaws.com/secure.notion-static.com/49dc6b8b-e6ea-4bd3-af6e-e622c55909b7/Untitled.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;유니코드에 할당된 문자의 값을 표현하기 위해서는 코드 포인트(code point)를 사용하고 U+를 붙여서 표시합니다. ‘가’의 유니코드 값은 U+AC00과 같이 표기합니다. 자바스크립트에서는 문자열 내에서 ‘\uAC00’과 같이 표현하기도 합니다.&lt;/p&gt;

&lt;p&gt;이러한 코드 포인트를 인코딩하기 위한 방법으로 유니코드 변환 형식(Unicode Transformation Format, UTF) 인코딩과 국제 문자 세트(Universal Coded Character Set, UCS) 인코딩이 있습니다.&lt;/p&gt;

&lt;p&gt;즉 UTF-8과 같은 문자셋은 유니코드 코드 포인트를 인코딩하기 위한 방법 중 하나입니다. UTF를 유니코드와 동의어로 쓰는 경우가 간혹 있는데 유의하도록 합시다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;utf-8&quot;&gt;UTF-8&lt;/h1&gt;

&lt;p&gt;UTF-8은 유니코드를 위한 가변 길이 문자 인코딩 방식 중 하나로 Universal Coded Character Set + Transformation Format - 8-bit의 약자입니다.&lt;/p&gt;

&lt;p&gt;“가변 길이”란 한 글자를 표현하기 위해 정해진 바이트를 사용하는 것이 아니라 변할 수 있는 길이를 의미하며, UTF-8 인코딩은 유니코드 한 문자를 나타내기 위해 1바이트에서 4바이트를 사용합니다. 영문자와 같이 U+0000부터 U+007F 범위에 있는 문자들은 1바이트만 사용하며, 대부분의 문자는 2~3바이트를 사용하며, 4바이트로 표현되는 문자는 모두 다국어 기본 평면(BMP) 바깥의 유니코드 문자이며 거의 사용되지 않습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.notion.so/6d68316a41414be586c0bf84b272b4f9&quot;&gt;UTF-8의 구조&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;한글 ‘가’의 경우 유니코드 코드 포인트 U+AC00이고, 이를 이진수로 표현하면 1010110000000000이 됩니다. AC00은 000800-00FFFF 범위에 들어가므로 3개의 바이트를 사용하게 되고, 1110xxxx 10xxxxxx 10xxxxxx 과 같은 형태로 인코딩되어, x부분에 이진수 값을 대체하면 됩니다. 즉 x자리에 1010-110000-000000을 채워주면 ‘가’는 UTF-8로 인코딩했을 때 11101010 10110000 10000000 이 됩니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;utf-16&quot;&gt;UTF-16&lt;/h1&gt;

&lt;p&gt;UTF-16(16-bit Unicode Transformation Format)은 UTF-8과 마찬가지로 유니코드 문자 인코딩 방식의 하나입니다. 기본 다국어 평면(BMP)에 속하는 문자들은 그대로 16비트 값으로 인코딩이 되고, 그 이상의 문자는 특별히 정해진 방식으로 32비트로 인코딩이 됩니다.&lt;/p&gt;

&lt;p&gt;UTF-8은 기본 다국어 평면에 속하는 글자도 1~3바이트로 길이가 달라질 수 있었지만 UTF-16은 기본 다국어 평면의 글자는 모두 2바이트로 표현됩니다. UTF-8에서 ‘가’는 11101010 10110000 10000000이었지만, UTF-16에서의 ‘가’는 10101100 00000000입니다.&lt;/p&gt;

&lt;p&gt;UTF-16에서 유의할 점은 엔디언입니다. 엔디언이란 연속된 값을 배열하는 순서를 의미하며, 바이트의 배열 순서(Byte order)를 지칭할 때 사용하는 용어입니다. 큰 단위가 앞에 나오는 빅 엔디언(Big-endian, BE), 작은 단위가 앞에 나오는 리틀 엔디언(Little-endian, LE)으로 나눌 수 있으며 이 외에 미들 엔디언이 있습니다.&lt;/p&gt;

&lt;p&gt;빅 엔디언은 사람이 숫자를 쓰는 것과 같이 큰 수가 앞쪽에 작은 수가 뒷쪽에 오는 방식이고 리틀 엔디안은 그 반대입니다.&lt;/p&gt;

&lt;p&gt;예를 들어 10진수 12345는 빅 엔디언으로 쓰여있지만, 이를 리틀 엔디언으로 쓰면 54321이 됩니다. 마찬가지로 한글 ‘가’는 코드 포인트가 U+AC00으로 바이트로 나눠보면 AC와 00입니다. 이 경우 빅 엔디언으로는 AC00이 되고, 리틀 엔디언으로는 00AC가 됩니다.&lt;/p&gt;

&lt;p&gt;이를 UTF-16에 적용해 보면 한글 ‘가’는 빅 엔디언 UTF-16(UTF-16BE)으로는 10101100 00000000 이고, 리틀 엔디언(UTF-16LE)로는 00000000 10101100이 됩니다.&lt;/p&gt;

&lt;p&gt;빅 엔디언인지 리틀 엔디언인지 구분을 위해 BOM(Byte Order Mark, 바이트 순서 표시)를 사용하는 경우가 간혹 있습니다. BOM은 필수 사항은 아니며, BOM을 쓰려면 텍스트의 시작 부분에 나와야 합니다. (예 - 텍스트 파일의 가장 첫 부분에 BOM 코드가 들어감). BOM은 유니코드에 U+FEFF로 정의되어 있습니다.&lt;/p&gt;

&lt;p&gt;UTF-16에서의 빅 엔디언 BOM은 FE FF이고, 리틀 엔디언은 FF FE입니다. BOM 문자는 가끔 필요할 수 있지만,  보이는 글자가 아니라서 사람이 식별할 수 없고(BOM이 있어도 텍스트 에디터 등으로 파일을 열어도 표시되지 않습니다.) 텍스트 파일을 읽거나, 네트워크로 텍스트를 전송할 때 문제가 될 수 있으므로 유의해야 합니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://wiki.hash.kr/index.php/%EC%9D%B8%EC%BD%94%EB%94%A9&quot;&gt;해시넷 - 인코딩&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%AC%B8%EC%9E%90_%EC%9D%B8%EC%BD%94%EB%94%A9&quot;&gt;위키피디아 - 문자 인코딩&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C&quot;&gt;위키피디아 - 유니코드&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/UTF-8&quot;&gt;위키피디아 - UTF-8&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/UTF-16&quot;&gt;위키피디아 - UTF-16&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%97%94%EB%94%94%EC%96%B8&quot;&gt;위키피디아 - 엔디언&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%B0%94%EC%9D%B4%ED%8A%B8_%EC%88%9C%EC%84%9C_%ED%91%9C%EC%8B%9D&quot;&gt;위키피디아 - BOM&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/19187&quot;&gt;Naver D2 - 한글 인코딩의 이해 1편: 한글 인코딩의 역사와 유니코드&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/76650&quot;&gt;Naver D2 - 한글 인코딩의 이해 2편:&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>nnoco</name></author><category term="javascript" /><category term="character set" /><category term="charset" /><category term="unicode" /><category term="utf-8" /><summary type="html">컴퓨터는 결국 0과 1로 표현됩니다. 우리가 컴퓨터를 사용하면서 보는 글자, 이미지, 파일 등도 어떤 방식으로든 0과 1로 저장이되거나 전송이 됩니다. 그래서 0과 1로 변환하는 것을 인코딩(Encoding, 부호화)이라고 하며, 이 중 글자를 0과 1로 변환하는 것을 문자 인코딩(Character Encoding)이라고 합니다.</summary></entry><entry><title type="html">자바스크립트 문자열 표현하기</title><link href="https://nnoco.github.io/study/gardenist/2020/05/01/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AC%B8%EC%9E%90%EC%97%B4-%ED%91%9C%ED%98%84%ED%95%98%EA%B8%B0.html" rel="alternate" type="text/html" title="자바스크립트 문자열 표현하기" /><published>2020-05-01T13:47:15+09:00</published><updated>2020-05-01T13:47:15+09:00</updated><id>https://nnoco.github.io/study/gardenist/2020/05/01/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AC%B8%EC%9E%90%EC%97%B4-%ED%91%9C%ED%98%84%ED%95%98%EA%B8%B0</id><content type="html" xml:base="https://nnoco.github.io/study/gardenist/2020/05/01/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AC%B8%EC%9E%90%EC%97%B4-%ED%91%9C%ED%98%84%ED%95%98%EA%B8%B0.html">&lt;p&gt;문자열은 텍스트를 다루기 위한 데이터입니다. 문서의 제목, 내용, 사용자의 ID, 비밀번호, 게시글에 보이는 내용 등 글자로 된 것들 그리고 지금 쓰고 있는 이 문서도 텍스트이고 문자열로 표현될 수 있습니다. 자바스크립트에서의 문자열은 문자열 리터럴(작은 따옴표 또는 큰 따옴표로 묶인 텍스트), String 함수, 또는 다른 객체의 toString() 메서드를 호출하여 표현할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 문자열 리터럴&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;literalString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Hello, String!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// String 함수&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stringFunction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Hello, String&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// String 함수에 문자열 리터럴을 전달&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stringFunction2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;1&quot;이 됩니다.&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// toString() 메서드 호출&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;toStringResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;123&quot;이 됩니다.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;단순히 원하는 텍스트를 따옴표 안에 넣음으로써 문자열을 표현할 수도 있지만, 줄바꿈, 탭과 같은 문자는 역슬래시()기호를 붙인 문자로 표현할 수 있습니다. 이를 이스케이프(Escape)라고 합니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tab&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Tab 문자&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newLine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 줄바꿈 문자&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;singleQuote&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\'&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 작은 따옴표(')로 둘러싼 문자열 안에서 작은 따옴표를 글자 그대로 쓰기&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;noProblem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 큰 따옴표 안의 작은 따옴표는 이스케이프 하지 않아도 됩니다.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doubleQuote&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 큰 따움표(&quot;)로 둘러싼 문자열 안에서 큰 따옴표를 글자 그대로 쓰기&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;줄바꿈의 경우에는 운영체제나 환경에 따라 Carriage Return 이라는 문자를 줄바꿈에 같이 쓰기도 합니다.&lt;/p&gt;

&lt;p&gt;타자기에서는 줄을 바꿀 때 잉크가 묻은 카트리지가 좌우로 움직이게 하는 캐리지를 줄 끝에서 다시 줄 처음으로 되돌려야 하고, 이를 캐리지 리턴이라고 합니다. 그리고 난 후 새로운 줄의 입력을 위해 종이를 밀어 올리는 Line Feed를 해줍니다. 이를 줄여서 캐리지 리턴을 CR, 라인 피드를 LF라고 하며, 이스케이프된 문자로는 각각 \r, \n 입니다. 그래서 간혹 텍스트 파일의 줄바꿈의 표현에 CR과 LF가 함께 있는 경우가 있어 파일을 읽은 후 줄 단위의 처리를 할 때 \r\n 형식으로 해줄 때도 있습니다.&lt;/p&gt;

&lt;p&gt;이스케이프 문자 외에 한국어 키보드에 없는 다른 국가의 문자나 이모지를 입력하려면 유니코드를 활용할 수 있습니다. 유니코드를 입력하기 위해서는 \u와 함께 16진수 4자리의 유니코드 값을 적어줍니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 제 성인 &quot;이&quot;의 한자를 유니코드 16진수로 표기하면 아래와 같습니다.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lastName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;u674e&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;李&quot; 출력&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;객체를 문자열로 표현하기 위해서 toString() 메서드를 호출하여 문자열을 얻을 수 있습니다. 객체 중 숫자(Number) 타입의 경우 toString() 메서드에 몇 진수로 표현할 것인지 인자로 전달할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1234&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;1234&quot; -&amp;gt; 10진수 그대로 문자열로 변환&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;10011010010&quot; -&amp;gt; 2진수로 표현된 1234&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;2322&quot; -&amp;gt; 8진수로 표현된 1234&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;4d2&quot; -&amp;gt; 16진수로 표현된 1234&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;10진수 이상은 알파벳을 사용하여 표현하며 toString의 인자로 최대 36까지 전달할 수 있으며, 36진수의 경우에는 숫자 0~9, 알파벳 a~z(26문자)로 구성됩니다. 2보다 적은 수 또는 36보다 큰 수를 전달하면 오류가 발생합니다.&lt;/p&gt;

&lt;p&gt;유니코드 중 이모지의 경우에는 조금 더 복잡합니다. &lt;a href=&quot;https://stackoverflow.com/questions/2219526/how-many-bytes-in-a-javascript-string&quot;&gt;자바스크립트는 하나의 글자를 위해 2byte를 사용&lt;/a&gt;합니다. 하지만 이모지는 4byte입니다. 그러므로 이모지는 보여지는 것은 한 글자이지만, 자바스크립트 내부적으로는 두 글자입니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;smile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;😀&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 한 글자이지만 2를 출력합니다.&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// charCodeAt&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;charCodeAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 55357 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;charCodeAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 56832 출력&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// codePointAt&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;codePointAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 128512 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;codePointAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 56832 출력&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://www.notion.so/gardenist/445666deae324c42892b4d3b79950ac4?showMoveTo=true&quot;&gt;문자와 문자열의 내부&lt;/a&gt;에서 charCodeAt은 UTF-16의 값을 반환하고, codePointAt은 유니코드 값을 반환한다고 했습니다. 스마일 이모지는 유니코드에는 하나의 글자와 값으로 정의하지만, UTF-16에는 Surrogate라는 방식으로 2byte 2개로 나누어 표현합니다.&lt;/p&gt;

&lt;p&gt;(아래는 깊게 보지 않아도 됩니다.)&lt;/p&gt;

&lt;p&gt;UTF-16에서 유니코드의 코드 값이 16진수 값으로 0x10000이 넘는 값은 코드 값에서 0x10000을 빼고, 뒤에서 10비트, 나머지 비트를 UTF-16의 “상위/하위 대체 영역”으로 표시된 Surrogate(상위 U+D800~U+DBFF, 하위 U+DC00~U+DFFF) 범위로 다시 대응시킵니다.&lt;/p&gt;

&lt;p&gt;위의 스마일의 codePointAt()의 호출 결과로 128512의 값을 얻었는데, 이를 Surrogate에 대응하기 위해서는 아래와 같이 계산합니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;유니코드 값 128512에서 0x10000(십진수로 65536) 을 뺍니다. → 62976&lt;/li&gt;
  &lt;li&gt;하위 10비트의 값을 구하기 위해 1024로 나눈 나머지를 구합니다 → 512&lt;/li&gt;
  &lt;li&gt;나머지 비트의 값을 구하기 위해 1024로 나누고 소수점은 버립니다 → 61&lt;/li&gt;
  &lt;li&gt;상위 Surrogate의 시작 값인 U+D800에 나머지 비트의 값인 61을 더합니다.&lt;/li&gt;
  &lt;li&gt;하위 Surrogate의 시작 값인 U+DC00에 하위 10비트의 값인 512를 구합니다.&lt;/li&gt;
  &lt;li&gt;이를 유니코드 이스케이프(\u16진수)로 표현해줍니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;이를 코드로 옮기면 아래와 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;smile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;😀&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;codePoint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;smile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;codePointAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 유니코드 값을 얻습니다.&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rebase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;codePoint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 0x10000을 빼줍니다. -&amp;gt; 62976&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;highSurrogate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rebase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 1024로 나눈 후 소수점 이하 버림&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lowSurrogate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rebase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 1024로 나눈 나머지를 구함&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;highSurrogate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xD800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 0xD800을 더함&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;lowSurrogate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xDC00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 0xDC00을 더함&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 결과를 16진수로 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;highSurrogate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// d83d 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lowSurrogate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// de00 출력&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 결과를 유니코드 이스케이프로 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ud83d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ude00&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 😀이 출력됩니다.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;조금 복잡한 내용을 다루었는데, UTF-16와 유니코드의 관계는 아래 문서에서 별도로 다루고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/study/gardenist/2020/05/01/문자-인코딩,-문자셋,-유니코드.html&quot;&gt;문자 인코딩, 문자셋, 유니코드&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://thekevinscott.com/emojis-in-javascript/&quot;&gt;https://thekevinscott.com/emojis-in-javascript/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://unicode.org/emoji/charts/full-emoji-list.html#1f600&quot;&gt;https://unicode.org/emoji/charts/full-emoji-list.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;문자와 인코딩 개념 정리 &lt;a href=&quot;https://devhoma.tistory.com/95&quot;&gt;https://devhoma.tistory.com/95&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;유니코드의 Surrogate Pair, Supplementary Character가 뭘까요? &lt;a href=&quot;https://www.sysnet.pe.kr/2/0/1710&quot;&gt;https://www.sysnet.pe.kr/2/0/1710&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Unicode Code Point와 Surrogates Pair &lt;a href=&quot;https://rookiecj.tistory.com/299&quot;&gt;https://rookiecj.tistory.com/299&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;위키피디아 - UTF-8 &lt;a href=&quot;https://ko.wikipedia.org/wiki/UTF-8&quot;&gt;https://ko.wikipedia.org/wiki/UTF-8&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;나무위키 - 유니코드 &lt;a href=&quot;https://namu.wiki/w/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C&quot;&gt;https://namu.wiki/w/유니코드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>nnoco</name></author><category term="javascript" /><category term="string" /><summary type="html">문자열은 텍스트를 다루기 위한 데이터입니다. 문서의 제목, 내용, 사용자의 ID, 비밀번호, 게시글에 보이는 내용 등 글자로 된 것들 그리고 지금 쓰고 있는 이 문서도 텍스트이고 문자열로 표현될 수 있습니다. 자바스크립트에서의 문자열은 문자열 리터럴(작은 따옴표 또는 큰 따옴표로 묶인 텍스트), String 함수, 또는 다른 객체의 toString() 메서드를 호출하여 표현할 수 있습니다.</summary></entry><entry><title type="html">자바스크립트 문자열 다루기</title><link href="https://nnoco.github.io/study/gardenist/2020/05/01/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%8B%A4%EB%A3%A8%EA%B8%B0.html" rel="alternate" type="text/html" title="자바스크립트 문자열 다루기" /><published>2020-05-01T13:44:58+09:00</published><updated>2020-05-01T13:44:58+09:00</updated><id>https://nnoco.github.io/study/gardenist/2020/05/01/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%8B%A4%EB%A3%A8%EA%B8%B0</id><content type="html" xml:base="https://nnoco.github.io/study/gardenist/2020/05/01/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%8B%A4%EB%A3%A8%EA%B8%B0.html">&lt;p&gt;자바스크립트의 문자열 타입인 String의 기능과 제공하는 함수들을 다뤄봅니다.&lt;/p&gt;

&lt;p&gt;String.fromCharCode()&lt;/p&gt;

&lt;p&gt;UTF-16의 문자 코드들을 전달하여 해당 문자 코드에 해당되는 문자로 변환하여 문자열을 반환합니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fromCharCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;189&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;43&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;190&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;61&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// ½+¾= 출력&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.fromCodePoint()&lt;/p&gt;

&lt;p&gt;유니코드 코드 포인트들을 전달하여 해당 유니코드 코드 포인드에 해당하는 문자로 변환되어 반환합니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fromCodePoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;44032&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// &quot;가&quot; 출력&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.chartAt(index)&lt;/p&gt;

&lt;p&gt;index에 위치한 문자를 반환합니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sentence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;동해물과 백두산이 마르고 닳도록&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sentence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;charAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 백&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 아래는 같은 기능을 하는 인덱스 연산자입니다.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sentence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 백&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.charCodeAt(index)&lt;/p&gt;

&lt;p&gt;index에 위치한 문자의 UTF-16의 문자 코드를 반환합니다.&lt;/p&gt;

&lt;p&gt;2바이트 문자의 경우 charCodeAt과 codePointAt은 글자의 반환 값이 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;안녕하세요&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;charCodeAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; 
&lt;span class=&quot;c1&quot;&gt;// 45397 출력&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.codePointAt(index)&lt;/p&gt;

&lt;p&gt;index에 위치한 문자의 유니코드 코드 포인트를 반환합니다.&lt;/p&gt;

&lt;p&gt;2바이트 문자의 경우 charCodeAt과 codePointAt은 글자의 반환 값이 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;안녕하세요&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;codePointAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; 
&lt;span class=&quot;c1&quot;&gt;// 45397 출력&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.concat(string, [, …string들])&lt;/p&gt;

&lt;p&gt;현재 문자열에 파라미터로 전달된 문자열들을 붙입니다.&lt;/p&gt;

&lt;p&gt;문자열에 + 연산자로 문자열을 붙이는 것과 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; World!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; Worl&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.includes(포함되어 있는지 확인할 문자열)&lt;/p&gt;

&lt;p&gt;현재 문자열에 파라미터로 전달된 문자열이 있는지 확인합니다. 있다면 true, 없으면 false입니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ell&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// false 출력 - 대소문자 구분&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.endsWith(찾을 문자열)&lt;/p&gt;

&lt;p&gt;현재 문자열이 파라미터로 전달된 찾을 문자열로 끝나는지 확인합니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fileName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;profile.png&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isPngFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;endsWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.png&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isPngFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true 출력&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.indexOf(찾을 문자열)&lt;/p&gt;

&lt;p&gt;현재 문자열에서 찾을 문자열로 시작하는 부분의 인덱스를 반환합니다. 만약 찾을 수 없다면 -1을 반환합니다.&lt;/p&gt;

&lt;p&gt;indexOf 함수는 인덱스를 앞에서부터 찾습니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Hello, World!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 처음으로 l이 나오는 인덱스인 2를 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;World&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// World의 시작 인덱스인 7을 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;안녕&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 안녕은 없으므로 -1 출력&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.lastIndexOf(찾을 문자열)&lt;/p&gt;

&lt;p&gt;현재 문자열에서 찾을 문자열로 시작하는 부분의 인덱스를 반환합니다. 만약 찾을 수 없다면 -1을 반환합니다.&lt;/p&gt;

&lt;p&gt;lastIndexOf 함수는 이름과 같이 뒤에서부터 찾습니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Hello, World!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 뒤에서부터 처음으로 l이 나오는 인덱스인 10을 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;World&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// World의 시작 인덱스인 7을 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;안녕&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 안녕은 없으므로 -1 출력&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.match(정규표현식)&lt;/p&gt;

&lt;p&gt;전달된 정규표현식에 일치되는 문자열이 포함된배열을 반환합니다.  (정규표현식은 별도로 다루도록 하겠습니다)&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;phoneNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;010-1234-4567&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;phoneNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\d{4}&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 숫자 4개가 매치된 결과를 반환&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 결과 배열&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;1234&quot; ]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 정규표현식에 global(전체 검색) 옵션 추가&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;phoneNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\d{4}&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 숫자 4개가 매치된 결과를 반환&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 결과 배열&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;1234&quot;, &quot;4567&quot; ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.padEnd(맞출 문자열의 길이 n, 채울 문자열)&lt;/p&gt;

&lt;p&gt;문자열의 길이가 파라미터로 전달된 문자열의 길이 n보다 짧으면 문자열의 뒷쪽에 채울 문자로 문자열의 길이를 맞춥니다. 채울 문자를 전달하지 않으면 공백 문자로 채워집니다.&lt;/p&gt;

&lt;p&gt;padEnd와 padStart가 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;padEnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;1    &quot;로 공백을 채워서 글자 길이를 4글자로 맞춤&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;padEnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;1***&quot;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;padEnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;XY&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;1XYX&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;String.prototype.padStart(맞출 문자열의 길이 n, 채울 문자열)&lt;/p&gt;

&lt;p&gt;문자열의 길이가 파라미터로 전달된 문자열의 길이 n보다 짧으면 문자열의 앞쪽에 채울 문자로 문자열의 길이를 맞춥니다. 채울 문자를 전달하지 않으면 공백 문자로 채워집니다.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;padStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;   1&quot; 출력&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;padStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;0001&quot; 출력&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 날짜 포맷을 맞추는 예제 (yyyy-MM-dd 형식)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;year&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFullYear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; 

&lt;span class=&quot;c1&quot;&gt;// 1~9월은 한자리이므로 0을 pad해주기&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 자바스크립트 month는 0부터 시작하므로 1을 더해줌&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;month&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getMonth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;padStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; 

&lt;span class=&quot;c1&quot;&gt;// 1~9일은 한자리이므로 0을 pad해주기&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// day는 1부터 시작함 ;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;day&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;padStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formatted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;month&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;formatted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 2020-03-21 출력&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;p&gt;참고자료&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;slice와 substring의 차이 &lt;a href=&quot;https://www.geeksforgeeks.org/javascript-difference-between-string-slice-and-string-substring/&quot;&gt;https://www.geeksforgeeks.org/javascript-difference-between-string-slice-and-string-substring/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>nnoco</name></author><category term="javascript" /><category term="string" /><summary type="html">자바스크립트의 문자열 타입인 String의 기능과 제공하는 함수들을 다뤄봅니다.</summary></entry></feed>