<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Hello My World!</title>
    <link>https://limdevbasic.tistory.com/</link>
    <description>개발 공부한 것 기록하는 블로그  </description>
    <language>ko</language>
    <pubDate>Mon, 8 Jun 2026 18:47:13 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>림 림</managingEditor>
    <image>
      <title>Hello My World!</title>
      <url>https://tistory1.daumcdn.net/tistory/3914974/attach/5d1fbb1760ac4140af2aa05ea66b026a</url>
      <link>https://limdevbasic.tistory.com</link>
    </image>
    <item>
      <title>[Java] Collection</title>
      <link>https://limdevbasic.tistory.com/29</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle Java 11 API와 다음 문서를 참고하여 공부하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html&quot;&gt;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1633408312462&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Collection (Java SE 11 &amp;amp; JDK 11 )&quot; data-og-description=&quot;Compares the specified object with this collection for equality. While the Collection interface adds no stipulations to the general contract for the Object.equals, programmers who implement the Collection interface &amp;quot;directly&amp;quot; (in other words, create a clas&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html&quot; data-og-url=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Collection (Java SE 11 &amp;amp; JDK 11 )&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Compares the specified object with this collection for equality. While the Collection interface adds no stipulations to the general contract for the Object.equals, programmers who implement the Collection interface &quot;directly&quot; (in other words, create a clas&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Index&lt;/span&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Class Hierarchy&lt;/span&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;인터페이스 계층 구조&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;클래스, 추상 클래스 포함 계층 구조&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;java.lang.Iterable&amp;lt;T&amp;gt; 인터페이스&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;java.lang.Collection&amp;lt;E&amp;gt; 인터페이스&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;java.util.List&amp;lt;E&amp;gt; 인터페이스&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;java.util.Queue&amp;lt;E&amp;gt; 인터페이스&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;java.util.Set&amp;lt;E&amp;gt; 인터페이스&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Interface Collection&amp;lt;E&amp;gt; 의 특징&lt;/span&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Type Parameter E&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Collection 구현 클래스의 생성자 컨벤션&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Optional Operator&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;equals() 메소드와 컬렉션 프레임워크 인터페이스의 멤버 메소드와의 관계&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Collection&amp;lt;E&amp;gt;의 멤버 메소드&lt;/span&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;int size()&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;boolean isEmpty()&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;boolean contains(Object o)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Iterator&amp;lt;E&amp;gt; iterator()&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Object[] toArray()&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;lt;T&amp;gt; T[] toArray(T[] a)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;dafault &amp;lt;T&amp;gt; T[] toArray(IntFunction&amp;lt;T[]&amp;gt; generator)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;boolean add(E e)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;boolean remove(Object o)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;boolean containsAll(Collection&amp;lt;?&amp;gt; c)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;boolean addAll(Collection&amp;lt;? extends E&amp;gt; c)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;boolean removeAll(Collection&amp;lt;?&amp;gt; c)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;default boolean removeIf(Predicate&amp;lt;? suber E&amp;gt; filter)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;boolean retainAll(Collection&amp;lt;?&amp;gt; c)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;void clear()&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;boolean equals(Object o)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;int hashCode()&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;default Spliterator&amp;lt;E&amp;gt; spliterator()&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;default Stream&amp;lt;E&amp;gt; stream()&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;default Stream&amp;lt;E&amp;gt; parallelStream()&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Class Hierarchy&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-1. 인터페이스 계층 구조&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고:&amp;nbsp;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/package-tree.html&quot;&gt;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/package-tree.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;494&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1Rxwh/btrgU2UXQhv/7wcKpg1GEufJweuSPIzink/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1Rxwh/btrgU2UXQhv/7wcKpg1GEufJweuSPIzink/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1Rxwh/btrgU2UXQhv/7wcKpg1GEufJweuSPIzink/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1Rxwh%2FbtrgU2UXQhv%2F7wcKpg1GEufJweuSPIzink%2Fimg.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;494&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-2. 클래스, 추상 클래스 포함 계층 구조&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고: &lt;a href=&quot;https://en.wikipedia.org/wiki/Java_collections_framework&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://en.wikipedia.org/wiki/Java_collections_framework&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1799&quot; data-filename=&quot;1920px-Java.util.Collection_hierarchy.svg.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQEnzr/btrgCDXn1vP/2k1UaRSRAnA95nLSMCZTG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQEnzr/btrgCDXn1vP/2k1UaRSRAnA95nLSMCZTG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQEnzr/btrgCDXn1vP/2k1UaRSRAnA95nLSMCZTG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQEnzr%2FbtrgCDXn1vP%2F2k1UaRSRAnA95nLSMCZTG0%2Fimg.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1799&quot; data-filename=&quot;1920px-Java.util.Collection_hierarchy.svg.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collection 인터페이스의 계층 구조는 위의 그림과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-3. java.lang.Iterable&amp;lt;T&amp;gt; 인터페이스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collection 인터페이스는 java.lang의 Iterable&amp;lt;T&amp;gt; 인터페이스를 확장하고 있습니다. Iterable&amp;lt;T&amp;gt; 인터페이스는 최상위 인터페이스로, 반복자를 통해 T 타입의 원소를 순회할 수 있도록 하는 인터페이스입니다. Iterable&amp;lt;T&amp;gt; 인터페이스를 구현하는 클래스는 for-each 문으로 원소를 순회할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-4. java.lang.Collection&amp;lt;E&amp;gt; 인터페이스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.lang의 Iterable&amp;lt;T&amp;gt; 인터페이스를 확장하는 java.util의 Collection&amp;lt;E&amp;gt; 인터페이스는 자바 컬렉션 프레임워크의 최상위 인터페이스입니다. 자바 컬렉션 프레임워크란 원소(클래스)를 담는 그룹인 컬렉션 자료구조를 표현하는 클래스와 인터페이스들을 말합니다. 서브 인터페이스들로는 java.util.List&amp;lt;E&amp;gt;, java.util.Queue&amp;lt;E&amp;gt;, java.util.Set&amp;lt;E&amp;gt;가 있습니다. 컬렉션에 따라 중복을 허용하는지, 순서가 있는지에 대한 특징들을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-5. java.util.List&amp;lt;E&amp;gt; 인터페이스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List는 순서가 있는 컬렉션입니다. List의 원소들은 저장된 순서에 따른 정수형의 인덱스로 접근할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List는 원소의 중복을 허용합니다. 원소 e1과 e2에 대해, e1.equals(e2)가 true인 원소의 저장이 가능합니다. 또, 여러 null값이나 null을 나타내는 원소를 저장할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List 인터페이스를 구현하는 클래스들로는 다음과 같은 것들이 있습니다. 이 중에 저에게 익숙한 클래스들로는 ArrayList, LinkedList, Stack, Vector가 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/AbstractList.html&quot;&gt;AbstractList&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/AbstractSequentialList.html&quot;&gt;AbstractSequentialList&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ArrayList.html&quot;&gt;ArrayList&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.management/javax/management/AttributeList.html&quot;&gt;AttributeList&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CopyOnWriteArrayList.html&quot;&gt;CopyOnWriteArrayList&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedList.html&quot;&gt;LinkedList&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.management/javax/management/relation/RoleList.html&quot;&gt;RoleList&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.management/javax/management/relation/RoleUnresolvedList.html&quot;&gt;RoleUnresolvedList&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Stack.html&quot;&gt;Stack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Vector.html&quot;&gt;Vector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-6. java.util.Queue&amp;lt;E&amp;gt; 인터페이스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Queue는 &lt;span style=&quot;color: #474747;&quot;&gt;FIFO (first-in-first-out)&lt;span&gt; 형태로 삽입과 삭제가 이루어지는 컬렉션입니다. 이 중에 Priority Queue는 예외입니다. 우선순위 큐는 큐에&amp;nbsp;&lt;span style=&quot;color: #474747;&quot;&gt;저장된 순서가 아니라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;제공되는 Comparator에 의해 식별된 우선순위에 따라 삭제가 이루어집니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Queue는 기본적인 컬렉션 메소드 외에 추가적인 삽입(Insert), 삭제(Remove), 검사(Examine) 작업을 제공합니다. 각각의 작업들은 두 가지 형태로 나뉘어집니다. 하나는 수행에 실패하면 예외를 발생시키는 것이고, 다른 하나는 null이나 false와 같은 특정 값을 리턴하는 방식입니다. 각각의 메소드는 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;258&quot; data-filename=&quot;스크린샷 2021-10-05 오후 2.26.34.png&quot; width=&quot;438&quot; height=&quot;145&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DzbuG/btrgTEmPSgi/nkiTSaBLcyuCvFjvh83ttK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DzbuG/btrgTEmPSgi/nkiTSaBLcyuCvFjvh83ttK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DzbuG/btrgTEmPSgi/nkiTSaBLcyuCvFjvh83ttK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDzbuG%2FbtrgTEmPSgi%2FnkiTSaBLcyuCvFjvh83ttK%2Fimg.png&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;258&quot; data-filename=&quot;스크린샷 2021-10-05 오후 2.26.34.png&quot; width=&quot;438&quot; height=&quot;145&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Queue 인터페이스를 구현하는 클래스들로는 다음과 같은 것들이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/AbstractQueue.html&quot;&gt;AbstractQueue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ArrayBlockingQueue.html&quot;&gt;ArrayBlockingQueue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ArrayDeque.html&quot;&gt;ArrayDeque&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ConcurrentLinkedDeque.html&quot;&gt;ConcurrentLinkedDeque&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ConcurrentLinkedQueue.html&quot;&gt;ConcurrentLinkedQueue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/DelayQueue.html&quot;&gt;DelayQueue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/LinkedBlockingDeque.html&quot;&gt;LinkedBlockingDeque&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/LinkedBlockingQueue.html&quot;&gt;LinkedBlockingQueue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedList.html&quot;&gt;LinkedList&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/LinkedTransferQueue.html&quot;&gt;LinkedTransferQueue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/PriorityBlockingQueue.html&quot;&gt;PriorityBlockingQueue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/PriorityQueue.html&quot;&gt;PriorityQueue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/SynchronousQueue.html&quot;&gt;SynchronousQueue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-7. java.util.Set&amp;lt;E&amp;gt; 인터페이스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Set은 수학에서의 집합을 추상화한 컬렉션입니다. 집합의 정의에서 알 수 있듯이, Set 컬렉션은 중복을 허용하지 않습니다. 따라서 Set을 구현하는 클래스의 생성자는 중복 원소가 없는 Set 클래스를 생성하도록 구현해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Set 인터페이스를 구현하는 클래스들로는 다음과 같은 것들이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/AbstractSet.html&quot;&gt;AbstractSet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ConcurrentHashMap.KeySetView.html&quot;&gt;ConcurrentHashMap.KeySetView&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ConcurrentSkipListSet.html&quot;&gt;ConcurrentSkipListSet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CopyOnWriteArraySet.html&quot;&gt;CopyOnWriteArraySet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/EnumSet.html&quot;&gt;EnumSet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashSet.html&quot;&gt;HashSet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/print/attribute/standard/JobStateReasons.html&quot;&gt;JobStateReasons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedHashSet.html&quot;&gt;LinkedHashSet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/TreeSet.html&quot;&gt;TreeSet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 자바 컬렉션 프레임워크의 계층 구조와 간단한 구성 요소들을 살펴보았습니다. 이제 Collection 인터페이스에 대해 더 자세히 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Interface Collection&amp;lt;E&amp;gt; 의 특징&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1. Type Parameter E&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 파라미터 E는 Collection의 원소의 타입을 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-2. Collection 구현 클래스의 생성자 컨벤션&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collection 인터페이스를 구현하는 클래스의 생성자는 2가지의 표준 생성자를 가져야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파라미터가 없는 기본 생성자&lt;/b&gt;:&amp;nbsp; 원소가 없는 빈 구현 타입의 컬렉션 클래스를 리턴합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하나의 파리미터를 가지는 생성자&lt;/b&gt;: Collection 타입의 하나의 파라미터를 가지는 생성자입니다. 파라미터로 받은 Collection과 같은 원소들을 가지는 구현 타입의 컬렉션 클래스를 리턴합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는 생성자를 가질 수 없기 때문에, 이 규칙을 강제하는 방법은 없습니다. 그래도 이 규칙을 알고 지키는 것이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-3. Optional Operator&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 Collection 구현 클래스가 특정 메소드를 구현하지 않을 것이라면,&amp;nbsp;&lt;span style=&quot;color: #474747;&quot;&gt;UnsupportedOperationException 예외를 발생시키는 메소드로 정의해야 합니다. 이런 메소드들은 Collection 인터페이스의 JavaDocs에 &quot;optional operation&quot;이라고 명세되어 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #474747;&quot;&gt;예를 들어, Collection 인터페이스의 add() 메소드의 JavaDocs 첫 번째 줄을 보면 optional operation이라고 되어 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1362&quot; data-origin-height=&quot;898&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.10.42.png&quot; width=&quot;645&quot; height=&quot;425&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oUoxe/btrgVNwVHDA/g58WO05hSKjzVWdZLpojk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oUoxe/btrgVNwVHDA/g58WO05hSKjzVWdZLpojk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oUoxe/btrgVNwVHDA/g58WO05hSKjzVWdZLpojk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoUoxe%2FbtrgVNwVHDA%2Fg58WO05hSKjzVWdZLpojk1%2Fimg.png&quot; data-origin-width=&quot;1362&quot; data-origin-height=&quot;898&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.10.42.png&quot; width=&quot;645&quot; height=&quot;425&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Collection 인터페이스를 구현하는 java.util.AbstractCollection&amp;lt;E&amp;gt; 클래스에서는 add() 메소드를 구현하고 있지 않습니다. 따라서 다음과 같이 UnsupportedOperationException 예외를 발생시키고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;734&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.11.34.png&quot; width=&quot;603&quot; height=&quot;337&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LM4rl/btrgGs2eenU/lvsxp0Yo4uwKFy9uqU6EJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LM4rl/btrgGs2eenU/lvsxp0Yo4uwKFy9uqU6EJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LM4rl/btrgGs2eenU/lvsxp0Yo4uwKFy9uqU6EJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLM4rl%2FbtrgGs2eenU%2Flvsxp0Yo4uwKFy9uqU6EJk%2Fimg.png&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;734&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.11.34.png&quot; width=&quot;603&quot; height=&quot;337&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-4. equals() 메소드와 컬렉션 프레임워크 인터페이스의 멤버 메소드와의 관계&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션 프레임워크 인터페이스의 많은 멤버 베소드들은 equals() 메소드와 의미적으로 밀접하게 연관되어 있습니다. 예를 들어, Collection 인터페이스의 contains(Object o) 메소드는 o.equals(e) 인 원소 e가 하나라도 있으면 true를 반환합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1302&quot; data-origin-height=&quot;412&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.14.31.png&quot; width=&quot;708&quot; height=&quot;224&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckBnB7/btrgMtzZjAc/kOSU0EjgsH18sudK57NK11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckBnB7/btrgMtzZjAc/kOSU0EjgsH18sudK57NK11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckBnB7/btrgMtzZjAc/kOSU0EjgsH18sudK57NK11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckBnB7%2FbtrgMtzZjAc%2FkOSU0EjgsH18sudK57NK11%2Fimg.png&quot; data-origin-width=&quot;1302&quot; data-origin-height=&quot;412&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.14.31.png&quot; width=&quot;708&quot; height=&quot;224&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미상으로 o.equals(e)인 원소가 있으면 true를 반환하지만, 실제로 모든 원소에 대해 o.equals(e)를 실행한다는 의미는 아닙니다. Collection 구현 클래스는 equals()를 실행하는 대신 다른 방법으로 비교하며 자유롭게 최적화를 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Collection&amp;lt;E&amp;gt;의 멤버 메소드&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-1. int size()&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1298&quot; data-origin-height=&quot;246&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.26.46.png&quot; width=&quot;733&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wJ9gu/btrgMusec6G/a92MhZf728Fpybc8coNMHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wJ9gu/btrgMusec6G/a92MhZf728Fpybc8coNMHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wJ9gu/btrgMusec6G/a92MhZf728Fpybc8coNMHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwJ9gu%2FbtrgMusec6G%2Fa92MhZf728Fpybc8coNMHk%2Fimg.png&quot; data-origin-width=&quot;1298&quot; data-origin-height=&quot;246&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.26.46.png&quot; width=&quot;733&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원소의 개수를 int형으로 반환합니다. 만약 원소의 개수가 Integer.MAX_VALUE 값보다 많다면, Integer.MAX_VALUE 값을 리턴합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-2. boolean isEmpty()&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;174&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.28.39.png&quot; width=&quot;493&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cocRj4/btrgTEgdPle/awYKjvdCNopYSIRby4HjHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cocRj4/btrgTEgdPle/awYKjvdCNopYSIRby4HjHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cocRj4/btrgTEgdPle/awYKjvdCNopYSIRby4HjHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcocRj4%2FbtrgTEgdPle%2FawYKjvdCNopYSIRby4HjHK%2Fimg.png&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;174&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.28.39.png&quot; width=&quot;493&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션에 원소가 없으면 true를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-3. boolean contains(Object o)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;402&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.30.10.png&quot; width=&quot;785&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp6a83/btrgMAyHHD5/m4RCBDBazBmICbip72nq5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp6a83/btrgMAyHHD5/m4RCBDBazBmICbip72nq5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp6a83/btrgMAyHHD5/m4RCBDBazBmICbip72nq5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp6a83%2FbtrgMAyHHD5%2Fm4RCBDBazBmICbip72nq5k%2Fimg.png&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;402&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.30.10.png&quot; width=&quot;785&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션이 특정 원소를 포함하고 있으면 true를 반환합니다. 2-4 절에서 살펴봤듯이, o.euqals(e)가 true인 원소가 하나라도 있으면 true를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 원소의 타입이 컬렉션에 맞지 않으면 ClassCastExecption 예외를 발생시킬 수 있습니다. 특정 원소가 null인데 컬렉션이 null 원소를 허용하지 않을 경우, NullPointerException 예외를 발생시킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-4. Iterator&amp;lt;E&amp;gt; iterator()&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;270&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.34.42.png&quot; width=&quot;758&quot; height=&quot;156&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2O7IO/btrgRMeiu6i/I2nyJk1OAvA7Ar1dLNLKsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2O7IO/btrgRMeiu6i/I2nyJk1OAvA7Ar1dLNLKsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2O7IO/btrgRMeiu6i/I2nyJk1OAvA7Ar1dLNLKsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2O7IO%2FbtrgRMeiu6i%2FI2nyJk1OAvA7Ar1dLNLKsK%2Fimg.png&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;270&quot; data-filename=&quot;스크린샷 2021-10-05 오후 3.34.42.png&quot; width=&quot;758&quot; height=&quot;156&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션의 반복자를 리턴합니다. 리턴되는 원소에 대한 순서를 보장하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-5. Object[] toArray()&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;518&quot; data-filename=&quot;스크린샷 2021-10-05 오후 4.06.19.png&quot; width=&quot;774&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Etnwb/btrgTFzv9YM/bMIddkLTLgGTpVkHO4NAGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Etnwb/btrgTFzv9YM/bMIddkLTLgGTpVkHO4NAGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Etnwb/btrgTFzv9YM/bMIddkLTLgGTpVkHO4NAGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEtnwb%2FbtrgTFzv9YM%2FbMIddkLTLgGTpVkHO4NAGk%2Fimg.png&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;518&quot; data-filename=&quot;스크린샷 2021-10-05 오후 4.06.19.png&quot; width=&quot;774&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션에 있는 모든 원소들을 배열로 반환합니다. 만약 컬렉션이 원소의 순서를 보장하는 컬렉션이라면, 그 순서대로 배열에 담아져서 리턴됩니다. 런타임에 배열의 원소의 타입은 Object입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반환되는 배열에 해당하는 컬렉션의 참조가 없습니다. 따라서 toArray()를 호출한 클라이언트는 반환되는 배열을 자유롭게 수정해도 안전합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-6. &amp;lt;T&amp;gt; T[] toArray(T[] a)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1346&quot; data-origin-height=&quot;1196&quot; data-filename=&quot;스크린샷 2021-10-05 오후 4.15.45.png&quot; width=&quot;697&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/npCNa/btrgVTcYNlf/Fnp58P7FgDbHNwYlz2CNf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/npCNa/btrgVTcYNlf/Fnp58P7FgDbHNwYlz2CNf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/npCNa/btrgVTcYNlf/Fnp58P7FgDbHNwYlz2CNf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnpCNa%2FbtrgVTcYNlf%2FFnp58P7FgDbHNwYlz2CNf0%2Fimg.png&quot; data-origin-width=&quot;1346&quot; data-origin-height=&quot;1196&quot; data-filename=&quot;스크린샷 2021-10-05 오후 4.15.45.png&quot; width=&quot;697&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 본 Object toArray()와 비슷하지만 런타임에서 반환되는 배열의 타입이 매개변수로 받은 a의 타입이라는 점이 다릅니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수 a는 컬렉션의 원소가 저장될 배열입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-7. dafault &amp;lt;T&amp;gt; T[] toArray(IntFunction&amp;lt;T[]&amp;gt; generator)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;992&quot; data-filename=&quot;스크린샷 2021-10-05 오후 4.24.25.png&quot; width=&quot;729&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MT6Ud/btrgOurXLPs/8W5uSX5KzDCjJK7o3X9xR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MT6Ud/btrgOurXLPs/8W5uSX5KzDCjJK7o3X9xR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MT6Ud/btrgOurXLPs/8W5uSX5KzDCjJK7o3X9xR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMT6Ud%2FbtrgOurXLPs%2F8W5uSX5KzDCjJK7o3X9xR1%2Fimg.png&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;992&quot; data-filename=&quot;스크린샷 2021-10-05 오후 4.24.25.png&quot; width=&quot;729&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 본 &amp;lt;T&amp;gt; T[] toArray(T[] a)와 비슷하지만 지정한 generator&lt;span style=&quot;color: #474747;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;function을 통해 생성한 T[] 타입의 배열에 원소를 담아준다는 점이 다릅니다. 내부적으로 &amp;lt;T&amp;gt; T[] toArray(T[] a)를 호출한 결과를 반환하고 있습니다.&lt;/span&gt;&lt;span style=&quot;color: #474747;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #474747;&quot;&gt;3-8. boolean add(E e)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;894&quot; data-filename=&quot;스크린샷 2021-10-05 오후 4.53.27.png&quot; width=&quot;704&quot; height=&quot;465&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLp6cb/btrgWEGsOab/ca4RiMpcB8KYL9xCdvGIaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLp6cb/btrgWEGsOab/ca4RiMpcB8KYL9xCdvGIaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLp6cb/btrgWEGsOab/ca4RiMpcB8KYL9xCdvGIaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLp6cb%2FbtrgWEGsOab%2Fca4RiMpcB8KYL9xCdvGIaK%2Fimg.png&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;894&quot; data-filename=&quot;스크린샷 2021-10-05 오후 4.53.27.png&quot; width=&quot;704&quot; height=&quot;465&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션에 특정 원소를 추가합니다. 만약 add() 메소드를 실행하고 컬렉션의 구성이 변화했다면 즉, 새로운 원소가 추가되었다면 true를 반환합니다. 만약 컬렉션이 중복을 허용하지 않는데 이미 특정 원소와 같은 값의 원소를 포함하고 있다면, false를 반환합니다. 이런 과정을 통해 특정 원소를 추가하는 것에 성공했든 안 했든, 특정 원소가 컬렉션에 포함되어 있다는 것을 보장해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;add() 메소드를 지원하는 컬렉션은 컬렉션에 추가될 수 있는 원소에 대한 제한을 가지고 있을 수 있습니다. 예를 들어, 어떤 컬렉션은 null을 허용하지 않을 수도 있고, 어떤 컬렉션은 특정 타입의 원소만 추가될 수 있도록 할 수 있습니다. 컬렉션 구현 클래스들은 JavaDocs와 같은 documentation에 원소의 제한에 대해 명확하게 명세해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 컬렉션이 매개변수로 받은 원소를 추가할 수 없다면, false를 리턴하는 대신 예외를 발생시켜야 합니다. 이렇게 하면 컬렉션에 항상 특정 타입의 원소만 포함되도록 보장할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-9. boolean remove(Object o)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;560&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.03.27.png&quot; width=&quot;786&quot; height=&quot;333&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdBaST/btrgMusqsw5/stLlyqQPG6cHGoMNNFSQO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdBaST/btrgMusqsw5/stLlyqQPG6cHGoMNNFSQO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdBaST/btrgMusqsw5/stLlyqQPG6cHGoMNNFSQO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdBaST%2FbtrgMusqsw5%2FstLlyqQPG6cHGoMNNFSQO0%2Fimg.png&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;560&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.03.27.png&quot; width=&quot;786&quot; height=&quot;333&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 원소가 컬렉션에 존재한다면 컬렉션에서 삭제합니다. 일반적으로, o.equals(e)가 true인 원소를 삭제합니다. 만약 컬렉션에서 원소를 삭제하는 것에 성공했다면, true를 반환합니다. add()와 마찬가지로 삭제에 실패했다면 예외를 발생시켜줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-10. boolean containsAll(Collection&amp;lt;?&amp;gt; c)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1334&quot; data-origin-height=&quot;474&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.05.35.png&quot; width=&quot;767&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ca56oV/btrgMy8PGfb/0n2x38TC6XHVOqvgPq3tik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ca56oV/btrgMy8PGfb/0n2x38TC6XHVOqvgPq3tik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ca56oV/btrgMy8PGfb/0n2x38TC6XHVOqvgPq3tik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fca56oV%2FbtrgMy8PGfb%2F0n2x38TC6XHVOqvgPq3tik%2Fimg.png&quot; data-origin-width=&quot;1334&quot; data-origin-height=&quot;474&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.05.35.png&quot; width=&quot;767&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션이 파라미터로 받은 특정 컬렉션의 모든 원소를 포함하고 있다면 true를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-11. boolean addAll(Collection&amp;lt;? extends E&amp;gt; c)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;746&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.06.50.png&quot; width=&quot;788&quot; height=&quot;372&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCAByI/btrgWEmcym9/EkDte4lqOWZFQ8nQ1QxnjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCAByI/btrgWEmcym9/EkDte4lqOWZFQ8nQ1QxnjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCAByI/btrgWEmcym9/EkDte4lqOWZFQ8nQ1QxnjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCAByI%2FbtrgWEmcym9%2FEkDte4lqOWZFQ8nQ1QxnjK%2Fimg.png&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;746&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.06.50.png&quot; width=&quot;788&quot; height=&quot;372&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터로 받은 특정 컬렉션에 있는 모든 원소들을 컬렉션에 추가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-12. boolean removeAll(Collection&amp;lt;?&amp;gt; c)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;608&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.16.56.png&quot; width=&quot;791&quot; height=&quot;354&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dYkywZ/btrgV8HQmT3/n3mJelnekkUYgo5FN55OHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dYkywZ/btrgV8HQmT3/n3mJelnekkUYgo5FN55OHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dYkywZ/btrgV8HQmT3/n3mJelnekkUYgo5FN55OHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdYkywZ%2FbtrgV8HQmT3%2Fn3mJelnekkUYgo5FN55OHk%2Fimg.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;608&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.16.56.png&quot; width=&quot;791&quot; height=&quot;354&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터로 받은 특정 컬렉션의 원소를 컬렉션에서 삭제합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-13. default boolean removeIf(Predicate&amp;lt;? suber E&amp;gt; filter)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1328&quot; data-origin-height=&quot;1064&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.19.21.png&quot; width=&quot;694&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ned7r/btrgOuTf2fN/0ysOw0QfFQ4mQgSzngdE1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ned7r/btrgOuTf2fN/0ysOw0QfFQ4mQgSzngdE1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ned7r/btrgOuTf2fN/0ysOw0QfFQ4mQgSzngdE1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fned7r%2FbtrgOuTf2fN%2F0ysOw0QfFQ4mQgSzngdE1k%2Fimg.png&quot; data-origin-width=&quot;1328&quot; data-origin-height=&quot;1064&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.19.21.png&quot; width=&quot;694&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터로 주어진 Predicate를 만족하는 원소들을 컬렉션에서 삭제합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 로직을 살펴보면 먼저 java.util.Objects 클래스의 requireNonNull() 정적 메소드를 이용하고 있습니다. Objects.requireNonNull()의 코드는 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;868&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.22.09.png&quot; width=&quot;653&quot; height=&quot;468&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxebSz/btrgGrCvL0b/bz34D9tcjvO1fNWJx4UodK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxebSz/btrgGrCvL0b/bz34D9tcjvO1fNWJx4UodK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxebSz/btrgGrCvL0b/bz34D9tcjvO1fNWJx4UodK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxebSz%2FbtrgGrCvL0b%2Fbz34D9tcjvO1fNWJx4UodK%2Fimg.png&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;868&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.22.09.png&quot; width=&quot;653&quot; height=&quot;468&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;T 타입의 객체를 받아 null이면 NullPointerException 예외를 발생시킵니다. 따라서 이 메소드를 실행하면 객체가 null인지 검사할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 현재 컬렉션의 iterator() 메소드를 통해 Iterator&amp;lt;E&amp;gt; 객체를 얻습니다. 그리고 이 반복자를 통해 컬렉션의 원소에 차례로 접근합니다. 각각의 컬렉션 원소를 filter.test()의 매개변수로 전달합니다. Predicate&amp;lt;T&amp;gt;의 boolean test(T t) 멤버 메소드는 predicate를 평가해서 조건을 만족하면 true를, 아니라면 false를 반환합니다. 따라서 파라미터로 주어진 Predicate인 filter를 만족하는 컬렉션의 원소들은 삭제됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-14. boolean retainAll(Collection&amp;lt;?&amp;gt; c)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;598&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.29.03.png&quot; width=&quot;762&quot; height=&quot;341&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o2W1Y/btrgIOKX9w8/LYmNsWmkmrtHmmQSAiXri0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o2W1Y/btrgIOKX9w8/LYmNsWmkmrtHmmQSAiXri0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o2W1Y/btrgIOKX9w8/LYmNsWmkmrtHmmQSAiXri0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo2W1Y%2FbtrgIOKX9w8%2FLYmNsWmkmrtHmmQSAiXri0%2Fimg.png&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;598&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.29.03.png&quot; width=&quot;762&quot; height=&quot;341&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터로 받은 컬렉션에 포함되는 원소만 유지하고 나머지는 컬렉션에서 삭제합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-15. void clear()&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;268&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.30.33.png&quot; width=&quot;766&quot; height=&quot;163&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kAN0Y/btrgGrJjLTy/Zo3QoZLvlkWtm62bZN2zO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kAN0Y/btrgGrJjLTy/Zo3QoZLvlkWtm62bZN2zO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kAN0Y/btrgGrJjLTy/Zo3QoZLvlkWtm62bZN2zO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkAN0Y%2FbtrgGrJjLTy%2FZo3QoZLvlkWtm62bZN2zO0%2Fimg.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;268&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.30.33.png&quot; width=&quot;766&quot; height=&quot;163&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션의 모든 원소들을 삭제합니다. clear() 메소드를 실행한 후에 컬렉션은 빈 상태가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-16. boolean equals(Object o)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;710&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.31.42.png&quot; width=&quot;761&quot; height=&quot;414&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZXCnt/btrgU0XTlTS/d7t5JRgEVeR53swdmeEdP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZXCnt/btrgU0XTlTS/d7t5JRgEVeR53swdmeEdP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZXCnt/btrgU0XTlTS/d7t5JRgEVeR53swdmeEdP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZXCnt%2FbtrgU0XTlTS%2Fd7t5JRgEVeR53swdmeEdP1%2Fimg.png&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;710&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.31.42.png&quot; width=&quot;761&quot; height=&quot;414&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 객체와 컬렉션의 동등성(equality)를 비교합니다. 동일성(identity)와 동등성(equality)에 대한 설명은 지난 포스팅(&lt;a href=&quot;https://limdevbasic.tistory.com/24&quot;&gt;2021.08.24 - [Java] - [Java] 동일성과 동등성(hashCode와 equals)&lt;/a&gt;)을 참고하실 수 있습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1633422836821&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java] 동일성과 동등성(hashCode와 equals)&quot; data-og-description=&quot;클래스의 객체를 비교할 때, 동일성을 비교할 것인지 동등성을 비교할 것인지를 명확하게 해야 할 때가 있습니다. 그렇다면 동일성과 동등성이란 무엇일까요? 동일성(Identity) 두 객체의 동일성&quot; data-og-host=&quot;limdevbasic.tistory.com&quot; data-og-source-url=&quot;https://limdevbasic.tistory.com/24&quot; data-og-url=&quot;https://limdevbasic.tistory.com/24&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dbsjhh/hyLRce1NW7/DbpDGFxWBFCgzVk1Dg6xY1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/dTfhAh/hyLQ8wUWYu/xoVlanA7M08Agl7KRNHtEk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cpfzA5/hyLRgBKYKB/44rTz80P61RhkT4aZyeQ1K/img.jpg?width=280&amp;amp;height=280&amp;amp;face=0_0_280_280&quot;&gt;&lt;a href=&quot;https://limdevbasic.tistory.com/24&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://limdevbasic.tistory.com/24&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dbsjhh/hyLRce1NW7/DbpDGFxWBFCgzVk1Dg6xY1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/dTfhAh/hyLQ8wUWYu/xoVlanA7M08Agl7KRNHtEk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cpfzA5/hyLRgBKYKB/44rTz80P61RhkT4aZyeQ1K/img.jpg?width=280&amp;amp;height=280&amp;amp;face=0_0_280_280');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java] 동일성과 동등성(hashCode와 equals)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;클래스의 객체를 비교할 때, 동일성을 비교할 것인지 동등성을 비교할 것인지를 명확하게 해야 할 때가 있습니다. 그렇다면 동일성과 동등성이란 무엇일까요? 동일성(Identity) 두 객체의 동일성&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;limdevbasic.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 List, Queue, Set과 같은 Java API를 이용하는 것이 아니라 Collection 인터페이스를 직접 구현하게 된다면, 프로그래머는 Object.equals() 메소드를 오버라이딩 할지 안할지 신중하게 생각해봐야 합니다. Value 비교를 할 것인지, Reference 비교를 할 것인지에 따라 equals() 오버라이딩의 여부가 결정됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;✋ List와 Set의 equals()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List의 equals()는 비교하는 &quot;List&quot;와 같을 때 true를, Set의 equals()는 비교하는 &quot;Set&quot;과 같을 때 true를 반환하도록 규정되어 있습니다.&lt;br /&gt;따라서 프로그래머가 직접 구현하는 컬렉션이 List와 Set을 구현하는 것이 아니라면, List나 Set과 비교했을 때 반드시 false를 반환해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-17. int hashCode()&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;352&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.45.46.png&quot; width=&quot;711&quot; height=&quot;191&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVDEAS/btrgRTdVaHA/E20OQjaKtiewUNCtCUdQtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVDEAS/btrgRTdVaHA/E20OQjaKtiewUNCtCUdQtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVDEAS/btrgRTdVaHA/E20OQjaKtiewUNCtCUdQtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVDEAS%2FbtrgRTdVaHA%2FE20OQjaKtiewUNCtCUdQtK%2Fimg.png&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;352&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.45.46.png&quot; width=&quot;711&quot; height=&quot;191&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션의 정수형 해시 코드 값을 반환합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Object.equals() 메소드를 오버라이딩한 컬렉션은 반드시 Object.hashCode()도 오버라이딩해야 합니다. 일반적으로 c1.equals(c2)는 c1.hashCode() == c2.hashCode()를 의미하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-18. default Spliterator&amp;lt;E&amp;gt; spliterator()&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1624&quot; data-origin-height=&quot;1232&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.48.25.png&quot; width=&quot;791&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2aaWi/btrgWEGAhX3/8zVI5OBACLqH5o1l2cQH21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2aaWi/btrgWEGAhX3/8zVI5OBACLqH5o1l2cQH21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2aaWi/btrgWEGAhX3/8zVI5OBACLqH5o1l2cQH21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2aaWi%2FbtrgWEGAhX3%2F8zVI5OBACLqH5o1l2cQH21%2Fimg.png&quot; data-origin-width=&quot;1624&quot; data-origin-height=&quot;1232&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.48.25.png&quot; width=&quot;791&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 8부터 추가되었으며, Iterator&amp;lt;E&amp;gt;의 메소드를 오버라이딩 한 메소드입니다. 컬렉션의 Spliterator 객체를 반환합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 더 효율적인 spliterator를 반환할 수 있는 서브클래스에서 오버라이딩되어야 합니다. 뒤에서 살펴볼 stream()과 parallelStream()의 laziness를 보존하기 위해, spliterator는 IMMUTABLE, CONCURRENT, 또는 late-binding 특성을 가져야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-19. default Stream&amp;lt;E&amp;gt; stream()&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;414&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.50.00.png&quot; width=&quot;792&quot; height=&quot;222&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QmfcC/btrgGsOZeMi/3n0Xwk1mD8m9uA7jeljom0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QmfcC/btrgGsOZeMi/3n0Xwk1mD8m9uA7jeljom0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QmfcC/btrgGsOZeMi/3n0Xwk1mD8m9uA7jeljom0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQmfcC%2FbtrgGsOZeMi%2F3n0Xwk1mD8m9uA7jeljom0%2Fimg.png&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;414&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.50.00.png&quot; width=&quot;792&quot; height=&quot;222&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 8부터 추가되었으며, 컬렉션의 sequential 스트림 객체를 반환합니다. spliterator() 메소드가 IMMUTABLE, CONCURRENT, 또는 late-binding인 spliterator를 반환할 수 없을 때 stream() 메소드가 오버라이드 되어야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-20. default Stream&amp;lt;E&amp;gt; parallelStream()&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;446&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.50.12.png&quot; width=&quot;793&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yMSKs/btrgWBbY2PB/WtACCqgFKzGEmmDmSydngK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yMSKs/btrgWBbY2PB/WtACCqgFKzGEmmDmSydngK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yMSKs/btrgWBbY2PB/WtACCqgFKzGEmmDmSydngK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyMSKs%2FbtrgWBbY2PB%2FWtACCqgFKzGEmmDmSydngK%2Fimg.png&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;446&quot; data-filename=&quot;스크린샷 2021-10-05 오후 5.50.12.png&quot; width=&quot;793&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 8부터 추가되었으며, 컬렉션의 possibly parallel한 스트림 객체를 반환합니다. spliterator() 메소드가 IMMUTABLE, CONCURRENT, 또는 late-binding인 spliterator를 반환할 수 없을 때 stream() 메소드가 오버라이드 되어야 합니다.&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>Collection</category>
      <category>Java</category>
      <category>자바</category>
      <category>컬렉션</category>
      <category>프레임워크</category>
      <author>림 림</author>
      <guid isPermaLink="true">https://limdevbasic.tistory.com/29</guid>
      <comments>https://limdevbasic.tistory.com/29#entry29comment</comments>
      <pubDate>Tue, 5 Oct 2021 18:06:28 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Nested Class(중첩 클래스) - Static Nested Class, Inner Class, Anonymous Class, Local Class</title>
      <link>https://limdevbasic.tistory.com/28</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 오라클 공식 문서와 Effective Java 서적을 참고하여 공부했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1631254008999&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Nested Classes (The Java&amp;trade; Tutorials &amp;gt;        
            Learning the Java Language &amp;gt; Classes and Objects)&quot; data-og-description=&quot;The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html&quot; data-og-url=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Nested Classes (The Java&amp;trade; Tutorials &amp;gt; Learning the Java Language &amp;gt; Classes and Objects)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Index&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Nested Class(중첩 클래스)란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 중첩 클래스를 사용할 때의 주의사항&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 중첩 클래스의 종류&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Inner Class(내부 클래스)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. Local Class(지역 클래스)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. Anonymous Class(익명 클래스)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. Static Nested Class(정적 중첩 클래스)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. Static Nested Class와 Inner Class 비교&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. 메모리 누수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Nested Class(중첩 클래스)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩 클래스란 흔히 멤버 클래스로도 알려져 있습니다. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;클래스 안에 멤버로 정의된 다른 클래스&lt;/span&gt;를 말합니다. 여기서 멤버로 '선언된' 클래스가 아니라 '정의된' 클래스임에 집중해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1631253727810&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class OuterClass {
    ...
    class NestedClass {
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드에서, NestedClass 클래스가 중첩 클래스에 해당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 중첩 클래스를 사용할 때의 주의사항&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩 클래스는 자신을 감싸고 있는 클래스에서만 쓰여야 합니다. 만약 그렇지 않고 외부의 다른 클래스에서도 사용되어야 한다면, 중첩 클래스로 정의하지 말고 외부의 클래스로 따로 정의해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 중첩 클래스의 종류&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩 클래스는 먼저 두 종류로 나뉘어집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;Static(정적): Static Nested Class&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;&lt;b&gt;Non-&lt;/b&gt;static(비정적): Inner Class&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;static&lt;/i&gt; 키워드로 선언된 &lt;b&gt;정적 클래스는 Static Nested Class(정적 중첩 클래스)&lt;/b&gt;라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비정적 클래스는 Inner Class(내부 클래스)&lt;/b&gt;라고 합니다. 비정적 클래스는 다시 비정적 중첩 클래스, 익명 클래스, 지역 클래스의 세 가지의 클래스로 나뉘어집니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 중첩 클래스는 이렇게 총 네 가지의 클래스로 분류할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;Static Nested Class(정적 중첩 클래스)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;Non-static Nested Class(비정적 중첩 클래스)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;Anonymous Class(익명 클래스)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;Local Class(지역 클래스)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Inner Class(내부 클래스)&lt;/h2&gt;
&lt;pre id=&quot;code_1631257419159&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class OuterClass {
	...
    class InnerClass {
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;특징&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InnerClass는 static 키워드 없이 선언됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InnerClass는 OuterClass에 선언된 모든 멤버에 접근할 수 있습니다. private로 선언된 멤버에도 접근할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InnerClass는 static 멤버를 선언할 수 없습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InnerClass의 인스턴스는 항상 OuterClass의 인스턴스와 함께 OuterClass의 내부에 존재합니다. (암묵적으로 OuterClass 인스턴스와 연결됩니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;내부 클래스의 객체 생성 방법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 클래스는 항상 자신을 감싸는 클래스의 객체와 함께 존재하기 때문에, 내부 클래스의 객체를 생성하기 위해서는 먼저 외부 클래스의 객체를 생성해야 합니다. 그리고 나서 내부 클래스의 객체를 생성해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1631257902244&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Local Class(지역 클래스)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 중첩 클래스의 종류를 살펴보면서, 내부 클래스에는 익명 클래스와 지역 클래스가 포함된다고 했습니다. 먼저 지역 클래스에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Local Class란, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;block에 정의된 클래스&lt;/span&gt;를 말합니다. 여기서 말하는 block이란, 여러 statements를 감싸고 있는 하나의 중괄호 쌍을 의미합니다. 예를 들어, Local Class는 메서드, for문, if문 등의 모든 block에서 선언될 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1631259532357&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LocalClassExample {
    ...
    public void methodExample() {
        ...
        class LocalClass {
            ...
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;특징&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Local Class는 자신을 감싸고 있는 block의 모든 멤버에 접근할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비정적 문맥에서 사용될 때만 Outer Class 인스턴스를 참조할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Local Class는 static 멤버를 가질 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 final static 키워드가 붙은 상수는 선언할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1631290951371&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LocalClassExample {

    public void methodExample() {

        class LocalClass {
            public static final int MAX = 10;
            public static final String F = &quot;female&quot;;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. Anonymous Class(익명 클래스)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익명 클래스는 이름이 없는 지역 클래스와 같다고 볼 수 있습니다. 익명 클래스는 선언과 동시에 초기화가 이루어집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익명 클래스의 한 가지 예로는 다음과 같이 GUI가 있는 애플리케이션에서 컴포넌트에 이벤트 리스터를 등록할 때 쓰입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1631893972856&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익명 클래스는 코드를 더 간결하게 만들어줍니다. 로컬 클래스가 한번만 사용되어진다면 익명 클래스를 사용하는 것이 좋습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;특징&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Anonymous Class는 Outer Class의 지역 변수가 final로 선언되어야 접근할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비정적인 문맥에서 사용될 때만 Outer Class의 인스턴스를 참조할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Local Class와 같이 static 멤버를 가질 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멤버 인터페이스를 선언할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. Static Nested Class(정적 중첩 클래스)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 Inner Class와 Inner Class의 일종인 Local Class, Anonymous Class에 대해 알아보았습니다. 이번엔 Static Nested Class에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Static Nested Class는 static 키워드와 함께 선언된 정적 중첩 클래스입니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1631895678421&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;특징&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static 키워드와 함께 선언됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자신을 감싸고 있는 클래스의 멤버에 접근할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자신을 감싸고 있는 클래스의 static 멤버에만 접근할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static이기 때문에, JVM 클래스 로딩 매커니즘에 의해 클래스 로딩 시점에 한 번만 호출됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. Static Nested Class와 Inner Class 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Static Nested Class와 Inner Class는 둘 다 클래스 안에 선언된 클래스라는 점에서 공통점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 구문상으로는 다음과 같이 static이 쓰였는지 아닌지의 차이만 있지만, 의미상 차이는 꽤 큽니다.&lt;/p&gt;
&lt;pre id=&quot;code_1631255131819&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class OuterClass {
    ...
    class InnerClass {
        ...
    }
    static class StaticNestedClass {
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;차이점 1) Outer Class의 멤버에 접근&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 IntelliJ에서 코드를 작성해 보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;810&quot; data-filename=&quot;스크린샷 2021-09-18 오후 3.52.05.png&quot; width=&quot;559&quot; height=&quot;412&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPheQq/btrfnOeQoEi/jtpiUrK5uod9Dhv9dat0tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPheQq/btrfnOeQoEi/jtpiUrK5uod9Dhv9dat0tK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPheQq/btrfnOeQoEi/jtpiUrK5uod9Dhv9dat0tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPheQq%2FbtrfnOeQoEi%2FjtpiUrK5uod9Dhv9dat0tK%2Fimg.png&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;810&quot; data-filename=&quot;스크린샷 2021-09-18 오후 3.52.05.png&quot; width=&quot;559&quot; height=&quot;412&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;line:15에서 'Non-static field 'outerField' cannot be referenced from a static context'라는 메세지와 함께 컴파일 에러가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Static Nested Class는 Outer Class의 static 멤버에만 접근할 수 있다(private 포함)&lt;/b&gt;는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 &lt;b&gt;Inner Class는 Outer Class의 모든 멤버에 접근할 수 있습니다.(private 포함)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Static Nested Class에서 Outer Class의 필드에 접근하기 위해서는 다음과 같이 Outer Class의 인스턴스를 참조하여야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;800&quot; data-filename=&quot;스크린샷 2021-09-18 오후 4.00.33.png&quot; width=&quot;557&quot; height=&quot;406&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ApIBG/btrfo5fEvDs/HbqJyKmQuNxwe9oOkhb0hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ApIBG/btrfo5fEvDs/HbqJyKmQuNxwe9oOkhb0hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ApIBG/btrfo5fEvDs/HbqJyKmQuNxwe9oOkhb0hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FApIBG%2Fbtrfo5fEvDs%2FHbqJyKmQuNxwe9oOkhb0hk%2Fimg.png&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;800&quot; data-filename=&quot;스크린샷 2021-09-18 오후 4.00.33.png&quot; width=&quot;557&quot; height=&quot;406&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;차이점2) 정규화된 this의 사용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 Inner Class에서 x, this.x, OuterClass.x의 값을 알아보는 코드를 작성했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;588&quot; data-filename=&quot;스크린샷 2021-09-18 오후 4.09.55.png&quot; width=&quot;684&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3VtNA/btrfnPEQH1c/rZKrb22FrwqpkH5epiEdk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3VtNA/btrfnPEQH1c/rZKrb22FrwqpkH5epiEdk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3VtNA/btrfnPEQH1c/rZKrb22FrwqpkH5epiEdk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3VtNA%2FbtrfnPEQH1c%2FrZKrb22FrwqpkH5epiEdk1%2Fimg.png&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;588&quot; data-filename=&quot;스크린샷 2021-09-18 오후 4.09.55.png&quot; width=&quot;684&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main 메서드에서 testShadowing 메서드를 실행해보면 각각 다음과 같은 값이 출력됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;x&lt;/b&gt;: testShadowing 메서드의 매개변수로 전달된 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;this.x&lt;/b&gt;: 1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;OuterClass.this.x&lt;/b&gt;: 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Inner Class의 인스턴스에서는 &lt;b&gt;정규화된 this를 통해서&amp;nbsp;&lt;/b&gt;Outer Class의 참조를 가져오거나 메서드를 실행할 수 있습니다&lt;/b&gt;. 정규화된 this란 &lt;i&gt;클래스명.this&amp;nbsp;&lt;/i&gt;와 같이 Outer Class의 이름을 명시하는 것을 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에, 다음 코드와 같이 Static Nested Class에서는 정규화된 this를 사용하려고 하면 컴파일 에러가 발생합니다.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;caret-color: transparent; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/W1Xnc/btrfqCqfi64/bC9aSL8xkNOPBEQK4H4H6k/img.png&quot; width=&quot;692&quot; height=&quot;305&quot; data-image-src=&quot;https://blog.kakaocdn.net/dn/W1Xnc/btrfqCqfi64/bC9aSL8xkNOPBEQK4H4H6k/img.png&quot; data-origin-width=&quot;1334&quot; data-origin-height=&quot;588&quot; data-filename=&quot;스크린샷 2021-09-18 오후 4.19.08.png&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;차이점 3) 인스턴스의 독립적 존재&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Inner Class에서 Outer Class의 정규화된 this를 사용할 수 있는 이유는, Inner Class의 인스턴스는 항상 Outer Class의 인스턴스와 함께 존재하고, 서로 연결되기 때문입니다. Inner Class의 인스턴스는 Outer Class 인스턴스 없이는 생성할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에, Static Nested Class의 인스턴스는 독립적으로 존재할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에, 개념상 Nested Class의 인스턴스가 Outer Class의 인스턴스와 독립적으로 존재할 수 있다면 Static Nested Class로 선언해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 메모리 누수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자로서 메모리를 관리하는 것은 굉장히 중요한 일입니다. 목적에 맞는 중첩 클래스를 선언해야 메모리 누수와 메모리 낭비를 막을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static 키워드를 생략한 Inner Class를 선언하면 Outer Class으로의 참조를 갖게 됩니다. 참조를 저장하려면 시간과 공간적인 측면에서 비용이 발생합니다. 그리고 가비지 컬렉션이 Outer Class 인스턴스를 수거하지 못하면 메모리 누수가 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;Nested Class에서 Outer Class에 접근할 일이 없다면 static을 붙여서 Static Nested Class로 선언하는 것이 가장 좋습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>Java</category>
      <category>Member Class</category>
      <category>Nested Class</category>
      <category>Non static Member Class</category>
      <category>Static Member Class</category>
      <category>멤버 클래스</category>
      <category>비정적 멤버 클래스</category>
      <category>자바</category>
      <category>정적 멤버 클래스</category>
      <category>중첩 클래스</category>
      <author>림 림</author>
      <guid isPermaLink="true">https://limdevbasic.tistory.com/28</guid>
      <comments>https://limdevbasic.tistory.com/28#entry28comment</comments>
      <pubDate>Sun, 19 Sep 2021 00:41:25 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Builder 생성자 패턴</title>
      <link>https://limdevbasic.tistory.com/27</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 생성하기 위해서는 public 생성자 또는 static 팩토리 메서드를 사용할 수 있습니다. 그런데 필수 매개변수가 아닌 선택 매개변수의 개수가 많을 경우, 코드의 효율성, 안정성, 가독성을 위해 Builder 패턴을 고려하는 것이 좋습니다. 여러 생성자 패턴과 그 장단점을 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Index&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 예제 클래스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Telescoping Constructor Pattern(점층적 생성자 패턴)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. JavaBeans Pattern(자바빈즈 패턴)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Builder Pattern(빌더 패턴)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 예제 클래스&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 2개의 &lt;b&gt;필수 멤버 필드&lt;/b&gt;와 4개의 &lt;b&gt;선택 멤버 필드&lt;/b&gt;를 가지는 Book 클래스가 있다고 합시다.&lt;/p&gt;
&lt;pre id=&quot;code_1631203013462&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.time.LocalDate;

public class Book {
    // 필수 멤버 필드
    private String title;
    private String author;

    // 선택 멤버 필드
    private String color;
    private int pages;
    private LocalDate publicationDate;
    private String weight;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Book 클래스의 생성자를 작성하는 3가지 방법에 대해 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Telescoping Constructor Pattern(점층적 생성자 패턴)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 단순하게는 필수 매개변수 2개를 받는 생성자부터 시작해서 3개를 받는 생성자, 4개를 받는 생성자, &amp;bull;&amp;bull;&amp;bull; 총 6개를 받는 생성자까지 모두 작성할 수 있습니다. 점층적 생성자 패턴은 이렇게 &lt;b&gt;필요할 수 있는 모든 매개변수 조합의 생성자를 작성하는 방법&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생성자 코드&lt;/h4&gt;
&lt;pre id=&quot;code_1631203240240&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.time.LocalDate;

public class Book {
    // 필수 멤버 필드
    private String title;
    private String author;

    // 선택 멤버 필드
    private String color;
    private int pages;
    private LocalDate publicationDate;
    private String weight;
    
    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }

    public Book(String title, String author, String color) {
        this.title = title;
        this.author = author;
        this.color = color;
    }

    public Book(String title, String author, String color, int pages) {
        this.title = title;
        this.author = author;
        this.color = color;
        this.pages = pages;
    }

    public Book(String title, String author, String color, int pages, LocalDate publicationDate) {
        this.title = title;
        this.author = author;
        this.color = color;
        this.pages = pages;
        this.publicationDate = publicationDate;
    }

    public Book(String title, String author, String color, int pages, LocalDate publicationDate, String weight) {
        this.title = title;
        this.author = author;
        this.color = color;
        this.pages = pages;
        this.publicationDate = publicationDate;
        this.weight = weight;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점층적 생성자 패턴으로 작성된 생성자를 이용해서 객체를 생성하려면, 원하는 매개변수를 포함한 생성자를 선택하여 사용하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체가 불완전한 상태에 있는 것을 방지할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 말하는 불완전한 상태란, 객체의 필수 멤버 필드의 값이 없는 상태를 말합니다. 생성할 때부터 필수 멤버 필드에 값을 초기화해주기 때문에, 객체가 항상 일관성을 유지할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라이언트 코드의 가독성이 떨어집니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수가 많아지면 많아질 수록, 코드를 읽을 때 각 매개변수의 순서와 개수를 주의해서 보아야 그 의미를 파악할 수 있습니다. 또, 타입이 같은 매개변수가 연달아 있을 경우, 컴파일 단계에서도 알아차릴 수 없는 버그가 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. JavaBeans Pattern(자바빈즈 패턴)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바빈즈 패턴은 &lt;b&gt;매개변수가 없는 생성자로 객체를 만든 후, setter 메서드로 멤버 필드의 값을 설정&lt;/b&gt;하는 방법입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생성자 코드&lt;/h4&gt;
&lt;pre id=&quot;code_1631203876528&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.time.LocalDate;

public class Book {
    // 필수 멤버 필드
    private String title;
    private String author;

    // 선택 멤버 필드
    private String color;
    private int pages;
    private LocalDate publicationDate;
    private String weight;

    public void setTitle(String title) {
        this.title = title;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public void setPages(int pages) {
        this.pages = pages;
    }

    public void setPublicationDate(LocalDate publicationDate) {
        this.publicationDate = publicationDate;
    }

    public void setWeight(String weight) {
        this.weight = weight;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드에서는 생성자가 없습니다. 생성자를 작성하지 않으면 Java에서 자동으로 기본 생성자를 만들어 줍니다. 자바빈즈 패턴으로 작성된 생성자로 객체를 만들기 위해서는 다음과 같이 기본 생성자로 멤버 필드가 비어있는 객체를 생성한 후에 setter 메소드로 값을 채워줘야 합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클라이언트 코드&lt;/h4&gt;
&lt;pre id=&quot;code_1631204152245&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Book book = new Book();
book.setTitle(&quot;My Book&quot;);
book.setAuthor(&quot;me&quot;);
book.setColor(&quot;black&quot;);
book.setPages(100);
book.setPublicationDate(LocalDate.now());
book.setWeight(&quot;3kg&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라이언트 코드의 가독성이 좋습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setter 메서드의 이름에 멤버 필드의 이름이 포함되어 있기 때문에, 어떤 멤버 필드에 어떤 값이 들어가는지 쉽게 파악할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체의 필수 멤버 필드에 값이 들어가기 전까지는 객체가 불완전한 상태에 놓입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 생성자로 객체를 생성한 직후에는 필수 멤버 필드에 빈 값이 들어가게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체 하나를 만들기 위해 여러 메서드가 호출됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 하나만 호출하면 되는 점층적 패턴과 달리, 자바빈즈 패턴은 여러 setter 메서드를 호출합니다. 매개변수가 많아질 수록 더 많은 메서드를 호출해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Builder Pattern(빌더 패턴)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌더 패턴은 점층적 생성자 패턴의 &lt;b&gt;안정성&lt;/b&gt;과 자바빈즈 패턴의 &lt;b&gt;가독성&lt;/b&gt;을 겸비한 패턴입니다. 빌더 패턴을 사용하는 일반적인 순서는 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 클래스 안에 static 멤버 클래스로 Builder 클래스를 만들어 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Builder 클래스는 생성할 클래스의 멤버 필드를 똑같이 가집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Builder 클래스의 선택 멤버 필드를 기본값으로 초기화합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Builder 클래스에 필수 멤버 필드를 매개변수로 하는 생성자를 선언합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 선택 매개변수의 값을 저장하고 Builder 객체를 반환하는 메서드를 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 생성할 클래스의 객체를 반환해주는 builder 메서드를 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 생성할 클래스의 생성자로 Builder 객체를 받는 생성자를 만듭니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생성자 코드&lt;/h4&gt;
&lt;pre id=&quot;code_1631205352678&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.time.LocalDate;

public class Book {
    // 필수 멤버 필드
    private String title;
    private String author;

    // 선택 멤버 필드
    private String color;
    private int pages;
    private LocalDate publicationDate;
    private String weight;

    // 1. 클래스 안에 static 멤버 클래스로 Builder 클래스를 만들어 줍니다.
    public static class Builder {
        // 2. Builder 클래스는 생성할 클래스의 멤버 필드를 똑같이 가집니다.
        private String title;
        private String author;

        // 3. Builder 클래스의 선택 멤버 필드를 기본값으로 초기화합니다.
        private String color = &quot;white&quot;;
        private int pages = 0;
        private LocalDate publicationDate = LocalDate.now();
        private String weight = &quot;0kg&quot;;

        // 4. Builder 클래스에 필수 멤버 필드를 매개변수로 하는 생성자를 선언합니다.
        public Builder(String title, String author) {
            this.title = title;
            this.author = author;
        }

        // 5. 선택 매개변수의 값을 저장하고 Builder 객체를 반환하는 메서드를 만듭니다.
        public Builder color(String color) {
            this.color = color;

            return this;
        }

        public Builder pages(int pages) {
            this.pages = pages;

            return this;
        }

        public Builder publicationDate(LocalDate publicationDate) {
            this.publicationDate = publicationDate;

            return this;
        }

        public Builder weight(String weight) {
            this.weight = weight;

            return this;
        }

        // 6. 생성할 클래스의 객체를 반환해주는 builder 메서드를 만듭니다.
        public Book build() {
            return new Book(this);
        }
    }

    // 7. 생성할 클래스의 생성자로 Builder 객체를 받는 생성자를 만듭니다.
    private Book(Builder builder) {
        title = builder.title;
        author = builder.author;
        color = builder.color;
        pages = builder.pages;
        publicationDate = builder.publicationDate;
        weight = builder.weight;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트는 필요한 객체를 생성자로 직접&amp;nbsp; 만들지 않습니다. 일반적으로 다음과 같은 방법으로 객체를 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 필수 매개변수로 이루어진 생성자를 통해 Builder 객체를 얻습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Builder 객체가 제공하는 메소드로 선택 멤버 필드의 값을 저장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 매개변수가 없는 build 메소드로 생성하고자 하는 클래스의 객체를 얻습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클라이언트 코드&lt;/h4&gt;
&lt;pre id=&quot;code_1631247605015&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Book b = new Book.Builder(&quot;title&quot;, &quot;author&quot;)
  .color(&quot;black&quot;)
  .pages(100)
  .publicationDate(LocalDate.now())
  .weight(&quot;2kg&quot;)
  .build();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;점층적 패턴의 안정성과 자바빈즈 패턴의 가독성을 모두 가집니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Builder 생성자를 통해 객체가 불완전한 상태에 있는 것을 방지해줍니다. Builder 멤버 메서드의 이름에 멤버 필드의 이름이 포함되어 있어서 가독성이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>constructor</category>
      <category>Java</category>
      <category>Pattern</category>
      <category>생성자 패턴</category>
      <category>자바</category>
      <category>자바빈 패턴</category>
      <author>림 림</author>
      <guid isPermaLink="true">https://limdevbasic.tistory.com/27</guid>
      <comments>https://limdevbasic.tistory.com/27#entry27comment</comments>
      <pubDate>Fri, 10 Sep 2021 13:52:35 +0900</pubDate>
    </item>
    <item>
      <title>[Java] JDBC에서 Class.forName과 클래스 로딩에 대해 알아보기</title>
      <link>https://limdevbasic.tistory.com/26</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;지난 포스팅에서 Java Reflection에 대해 다뤘습니다. JDBC를 사용할 때 쓰이는 Class.forName 역시 Java Reflection에서 제공하는 기능 중에 하나입니다. JDBC 를 사용하여 DB에 접근하기 위해서는 제일 먼저 드라이버 클래스를 로드해야 하는데, 그 때 Class.forName을 사용합니다. 이번 포스팅에서는 드라이버를 로드할 때 Class.forName이 어떻게 활용되는지 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 문서와 Java API를 참고하여 공부했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.baeldung.com/java-classloaders&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.baeldung.com/java-classloaders&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/9/migrate/toc.htm#JSMIG-GUID-A868D0B9-026F-4D46-B979-901834343F9E&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.oracle.com/javase/9/migrate/toc.htm#JSMIG-GUID-A868D0B9-026F-4D46-B979-901834343F9E&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.kdata.or.kr/info/info_04_view.html?dbnum=183810&quot;&gt;https://www.kdata.or.kr/info/info_04_view.html?dbnum=183810&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://pjh3749.tistory.com/250&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pjh3749.tistory.com/250&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Index&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. JDBC 작업의 일반적인 순서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 예제 코드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Class.forName의 역할에 대해 궁금한 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Class.forName JavaDocs 읽어보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. Class Loader의 종류와 계층 구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. Class Loading 시점에 따른 분류&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. JDBC 작업에서의 Class.forName 돌아보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. JDBC 작업의 일반적인 순서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDBC를 사용하여 DB에 접근하는 일반적인 순서는 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Driver 클래스 로드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. DB 연결을 위한 Connection 객체 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. SQL을 담는 Statement 또는 PreparedStatement 객체 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. SQL 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 리소스 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 예제 코드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 살펴본 순서에 대한 예제 코드는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630922465907&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. Driver 클래스 로드
Class.forName(&quot;com.mysql.cj.jdbc.Driver&quot;);

// 2. DB 연결을 위한 Connection 객체 생성
Connection connection = DriverManager.getConnection(&quot;jdbc:mysql://localhost/...&quot;);

// 3. SQL을 담는 PreparedStatement 객체 생성
PreparedStatement preparedStatement = connection.prepareStatement(
&quot;INSERT into user(id, name, password) values(?,?,?)&quot;
);
preparedStatement.setLong(1, 1);
preparedStatement.setString(2, &quot;name&quot;);
preparedStatement.setString(3, &quot;password&quot;);

// 4. SQL 실행
preparedStatement.executeUpdate();

// 5. 리소스 정리
preparedStatement.close();
connection.close();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL DBMS를 사용한다고 가정할 때, 맨 처음에 Driver 클래스를 로드하기 위해 Class.forName 메소드를 활용합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1630922501747&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Class.forName(&quot;com.mysql.cj.jdbc.Driver&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Class.forName의 역할에 대해 궁금한 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reflection을 공부할 때, Class는 실행 중인 자바 프로그램에서 클래스와 인터페이스를 표현하는(정보를 담는) 클래스라고 배웠습니다. 그리고 Class의 static 메소드인 forName은 클래스의 이름을 매개변수로 받아서 Class 객체를 리턴해줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 JDBC에서는 Driver 클래스를 JVM에 로드하기 위해서 Class.forName이 사용되고 있습니다. 그러면 Class.forName의 역할은 단지 클래스의 이름으로 Class 객체를 얻는 것이 아닌, JVM에 클래스를 로딩하는 역할도 하는 것일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Class.forName JavaDocs 읽어보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class.forName은 매개변수가 다른 두 개의 메소드가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 11 기준 &lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;forName&lt;/span&gt;(String className)&lt;/i&gt;의 JavaDocs를 읽어보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1252&quot; data-origin-height=&quot;556&quot; data-filename=&quot;스크린샷 2021-09-06 오후 11.14.54.png&quot; width=&quot;619&quot; height=&quot;275&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAe0Oo/btreaQD9gq0/6xAKI1S5IKSXuKVZVOc7o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAe0Oo/btreaQD9gq0/6xAKI1S5IKSXuKVZVOc7o0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAe0Oo/btreaQD9gq0/6xAKI1S5IKSXuKVZVOc7o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAe0Oo%2FbtreaQD9gq0%2F6xAKI1S5IKSXuKVZVOc7o0%2Fimg.png&quot; data-origin-width=&quot;1252&quot; data-origin-height=&quot;556&quot; data-filename=&quot;스크린샷 2021-09-06 오후 11.14.54.png&quot; width=&quot;619&quot; height=&quot;275&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;forName&lt;/span&gt;(String className)&lt;/i&gt;을 실행한 결과는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;Class.forName(className, true, currentLoader)를 실행한 결과와 같다&lt;/span&gt;고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;forName(String name, boolean initialize, ClassLoader loader)&lt;/span&gt;&lt;/i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;의 JavaDocs는 다음과 같습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;1170&quot; data-filename=&quot;스크린샷 2021-09-06 오후 11.16.59.png&quot; width=&quot;671&quot; height=&quot;594&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bojL2L/btrejVcZyJv/g2mGUCNmerfxEgoi7jXqQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bojL2L/btrejVcZyJv/g2mGUCNmerfxEgoi7jXqQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bojL2L/btrejVcZyJv/g2mGUCNmerfxEgoi7jXqQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbojL2L%2FbtrejVcZyJv%2Fg2mGUCNmerfxEgoi7jXqQ0%2Fimg.png&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;1170&quot; data-filename=&quot;스크린샷 2021-09-06 오후 11.16.59.png&quot; width=&quot;671&quot; height=&quot;594&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;클래스 로더에 의해 클래스 또는 인터페이스가 로드된다&lt;/span&gt;고 합니다. 별도의 클래스 로더를 지정하지 않으면 Bootstrap 클래스 로더에 의해 로드됩니다. Bootstrap 클래스 로더는 다음 절에서 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forName JavaDocs를 읽어보니 forName의 역할이 단지 Class 객체를 반환하는 것이 아니라 클래스 로더에 의해 그 클래스 객체가 로드된다는 것을 알 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Java Class Loader의 종류와 계층 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 로더는 런타임에 클래스들을 동적으로 JVM에 로드합니다. 애플리케이션이 클래스를 필요로 할 때 메모리에 적재합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 로더는 다음과 같은 계층 구조로 이루어져 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;297&quot; height=&quot;329&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;642&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n7kwy/btrec34CRPk/kCVoPi0QXuZasiX8JJCYMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n7kwy/btrec34CRPk/kCVoPi0QXuZasiX8JJCYMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n7kwy/btrec34CRPk/kCVoPi0QXuZasiX8JJCYMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn7kwy%2Fbtrec34CRPk%2FkCVoPi0QXuZasiX8JJCYMk%2Fimg.png&quot; width=&quot;297&quot; height=&quot;329&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;642&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;Bootstrap Class Loader&lt;/b&gt;: 모든 클래스들을 로드합니다. ($JAVA_HOME/jre/lib)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;Platform Class Loader&lt;/b&gt;: Java 표준 코어 클래스를 확장한 클래스를 로드합니다. ($JAVA_HOME/lib/ext, java.ext.dirs)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;System Class Loader&lt;/b&gt;: Classpath에 있는 클래스를 로드합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 계층에 있는 Class Loader는 그 역할을 상위 Class Loader에게 위임합니다. 상위 Class Loader는 각자가 맡은 경로에서 클래스를 찾아본 뒤, 없으면 다시 하위 클래스로 내려옵니다. 최하위 Class Loader에서 찾고자 하는 클래스를 찾을 수 없으면&lt;span style=&quot;color: #222426;&quot;&gt;ClassNotFoundException을 발생시킵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. Class Loading 시점에 따른 분류&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Load Time Dynamic Loading&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Load Time Dynamic Loading은 하나의 클래스를 로딩하는 시점에, 그 클래스에서 사용하는 다른 클래스들을 함께 로딩하는 것을 말합니다. 관련 클래스들은 아직 참조되지 않은 상태에서 JVM에 로드됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Run Time Dynamic Loading&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Run Time Dynamic Loading은 클래스가 참조되는 시점에 로딩하는 것을 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. JDBC에서 Class.forName 돌아보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDBC에서 Class.forName의 역할을 알아보기 위해 Class Loading의 종류와 과정에 대해 알아보았습니다. 결론적으로 아래의 코드에서 Class.forName을 통해 Mysql DBMS에 접근할 수 있는 JDBC Driver 클래스가 클래스 로더에 의해 로드된다는 것을 알 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630938857762&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Class.forName(&quot;com.mysql.cj.jdbc.Driver&quot;);

Connection connection = DriverManager.getConnection(&quot;jdbc:mysql://localhost/...&quot;);

PreparedStatement preparedStatement = connection.prepareStatement(
&quot;INSERT into user(id, name, password) values(?,?,?)&quot;
);
preparedStatement.setLong(1, 1);
preparedStatement.setString(2, &quot;name&quot;);
preparedStatement.setString(3, &quot;password&quot;);

preparedStatement.executeUpdate();

preparedStatement.close();
connection.close();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 왜 Driver driver = &lt;span style=&quot;color: #cc7832;&quot;&gt;new &lt;/span&gt;Driver()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;와 같이 객체를 생성하지 않고도 GC의 대상이 되지 않고 사용할 수 있는 것일까요? Driver 클래스의 내부 코드를 보았습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;972&quot; data-filename=&quot;스크린샷 2021-09-06 오후 11.53.54.png&quot; width=&quot;606&quot; height=&quot;427&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lcr0R/btred1egZmd/ckphkgMDZxESNwaDeh6bRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lcr0R/btred1egZmd/ckphkgMDZxESNwaDeh6bRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lcr0R/btred1egZmd/ckphkgMDZxESNwaDeh6bRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLcr0R%2Fbtred1egZmd%2FckphkgMDZxESNwaDeh6bRK%2Fimg.png&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;972&quot; data-filename=&quot;스크린샷 2021-09-06 오후 11.53.54.png&quot; width=&quot;606&quot; height=&quot;427&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static절은 클래스가 로딩되는 시점에 초기화를 위해 실행되는 부분입니다. Driver 클래스의 static 절의 내부에서 new Driver() 코드를 통해 인스턴스를 생성하고 있습니다. 그리고 DriverManager.registerDriver 메소드를 통해 Driver 인스턴스를 DriverManager에 등록합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 static 블록을 가지는 클래스들은 Class.forName을 호출하기만 해도 초기화가 실행되기 때문에, 인스턴스를 별도로 관리하지 않는 클래스에서 자주 활용된다고 합니다. 이렇게 static 블록에서 클래스 자기 자신의 인스턴스를 생성하고 관리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DriverManager.registerDriver 의 코드는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630940860253&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public static void registerDriver(java.sql.Driver driver)
        throws SQLException {

        registerDriver(driver, null);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1630940904769&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public static void registerDriver(java.sql.Driver driver,
            DriverAction da)
        throws SQLException {

        /* Register the driver if it has not already been added to our list */
        if (driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
        } else {
            // This is for compatibility with the original DriverManager
            throw new NullPointerException();
        }

        println(&quot;registerDriver: &quot; + driver);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if문으로 driver가 null이 아닌지 체크하고, addIfAbsent 메소드를 호출하고 있습니다. addIfAbsent 메소드는 그 이름에서 알 수 있듯이, 현재 DriverManager에 등록된 드라이버가 없을 때에만 드라이버를 등록해주는 메소드입니다. 따라서 Class.forName을 여러 번 호출하더라도 static절에 있는 new Driver() 코드에 의해 드라이버 객체가 계속 생성되는 것을 막아줍니다.&lt;/p&gt;</description>
      <category>Java</category>
      <category>Class Loader</category>
      <category>Class Loading</category>
      <category>Class.forName</category>
      <category>Java</category>
      <category>JDBC</category>
      <category>자바</category>
      <category>클래스 로더</category>
      <category>클래스 로딩</category>
      <author>림 림</author>
      <guid isPermaLink="true">https://limdevbasic.tistory.com/26</guid>
      <comments>https://limdevbasic.tistory.com/26#entry26comment</comments>
      <pubDate>Tue, 7 Sep 2021 00:13:24 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Reflection</title>
      <link>https://limdevbasic.tistory.com/25</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자바빈에 대해 공부하다가 자바빈은 디폴트 생성자를 가지고있어야 한다는 것을 알게 되었습니다. 그 이유는 툴이나 프레임워크에서 리플렉션을 이용하여 객체를 생성하기 때문이라고 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 리플렉션이 대략적으로 클래스에 대한 정보를 알아내는 기술이라고 알고 있었기 때문에, 리플렉션을 통해 어떻게 객체를 생성하는 것인지 궁금했습니다. 그래서 리플렉션에 대해 더 자세히 공부해보기로 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 오라클 문서를 참고하여 공부하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.oracle.com/technical-resources/articles/java/javareflection.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.oracle.com/technical-resources/articles/java/javareflection.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Index&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Reflection이란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 예제 코드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Reflection을 위한 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. instanceof 연산자 기능 실행하기: isInstance&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 클래스의 멤버 메소드 알아내기: getDeclaredMethods&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 클래스의 생성자 알아내기: getDeclaredConstructors&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 클래스의 멤버 필드 알아내기: getDeclaredFields&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. 메소드 실행하기: invoke&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. 새로운&lt;span&gt;&amp;nbsp;&lt;/span&gt;객체 생성하기: newInstance&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Reflection이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플렉션은 자바에서 제공하는 기능 중에 하나입니다. 리플렉션은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;실행 중인 자바 프로그램&lt;/span&gt;이 프로그램 자신의 정보를 알아낼 수 있고, 프로그램 자신의 속성(properties)을 조작할 수 있게 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 자바의 클래스는 리플렉션을 통해 자신의 모든 멤버의 이름을 알아낼 수 있고, 필드를 수정하거나 메소드를 실행할 수 있습니다. 리플렉션은 다른 언어에서는 찾아보기 힘든 자바만의 기술입니다. Pascal, C, C++에서는 이렇게 프로그램에 정의된 메소드의 정보를 알아내는 기능이 존재하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플렉션의 대표적인 사용 예는 JavaBeans입니다. JavaBeans이란, 빌더 툴을 통해 시각적으로 조작 가능한 소프트웨어 컴포넌트를 말합니다. 빌더 툴은 자바 프로그램을 실행하고 클래스들이 동적으로 로딩될 때, 리플렉션을 통해 그 클래스들에 대한 정보를 얻어냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 예제 코드&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 리플렉션이 어떻게 동작하는지 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 코드는 클래스의 이름으로 클래스에 정의된 멤버 메소드의 이름을 출력하는 코드입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630837094990&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.lang.reflect.*;

public class DumpMethods {
  public static void main(String args[])
  {
     try {
        Class c = Class.forName(args[0]);
        Method m[] = c.getDeclaredMethods();
        for (int i = 0; i &amp;lt; m.length; i++)
        System.out.println(m[i].toString());
     }
     catch (Throwable e) {
        System.err.println(e);
     }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드를 다음의 명령어로 실행해보겠습니다. 첫번째 인자로 &quot;java.util.Stack&quot;이라는 클래스의 이름을 입력해주고 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630837422638&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java DumpMethods java.util.Stack&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과:&lt;/p&gt;
&lt;pre id=&quot;code_1630837454946&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public java.lang.Object java.util.Stack.push(java.lang.Object)
public synchronized java.lang.Object java.util.Stack.pop()
public synchronized java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized int java.util.Stack.search(java.lang.Object)
public java.lang.Object java.util.Stack.push(java.lang.Object)
public synchronized java.lang.Object java.util.Stack.pop()
public synchronized java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized int java.util.Stack.search(java.lang.Object)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.util.Stack 클래스의 멤버 메소드들이 리턴 타입과 파라미터와 함께 출력되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Class.forName() 메소드로 특정 클래스를 얻어내고, getDeclaredMethods() 메소드를 호출해서 그 클래스에 정의된 메소드를 받아올 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 실행 중인 자바 프로그램에서 클래스의 정보를 알아내는 기술을 Reflection이라고 합니다. 그러면 본격적으로 Reflection 기술을 사용하는 방법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Reflection을 위한 설정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플렉션 관련 클래스들은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;java.lang.reflection 패키지&lt;/span&gt;에 있습니다. 이 클래스들을 활용하기 위해서는 제일 먼저 클래스에 대한 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;java.lang.Class&lt;/span&gt; 타입의 객체를 얻어야 합니다. java.lang.Class는 실행 중인 자바 프로그램에서 클래스와 인터페이스를 표현하는 클래스입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class 객체를 얻는 방법에는 세 가지가 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 클래스의 이름&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;Class.forName 메소드를 통해 클래스의 이름으로 Class 객체를 얻을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630837669425&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Class&amp;lt;?&amp;gt; c = Class.forName(&quot;java.lang.String&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forName 메소드는 다음과 같이 정의되어 있습니다. (Java 11)&lt;/p&gt;
&lt;pre id=&quot;code_1630837678279&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@CallerSensitive
public static Class&amp;lt;?&amp;gt; forName(String className) throws ClassNotFoundException {
  Class&amp;lt;?&amp;gt; caller = Reflection.getCallerClass();
  return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reflection.getCallerClass 메소드를 통해 이 메소드를 호출하고 있는 클래스의 정보를 받아옵니다. 그리고 forName0 네이티브 메소드를 호출한 결과를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스를 찾을 수 없으면 ClassNotFoundExcepion 예외를 발생시킵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 기본 자료형&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 방법으로 기본 자료형의 Class 객체를 얻을 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630837840277&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Class&amp;lt;?&amp;gt; c = int.class;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 기본 자료형의 Wrapper 클래스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 방법으로 기본 자료형의 Wrapper 클래스의 Class 객체를 얻을 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630837847005&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Class&amp;lt;?&amp;gt; c = Integer.TYPE;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TYPE 은 기본 자료형을 나타내는 Class 객체입니다. 내부적으로는 Class.getPrimitiveClass(&quot;int&quot;)를 호출한 것과 동일합니다. 불변객체이기 때문에 static final 키워드로 선언되어있는 모습을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630837859819&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SuppressWarnings(&quot;unchecked&quot;)
public static final Class&amp;lt;Integer&amp;gt;  TYPE = (Class&amp;lt;Integer&amp;gt;) Class.getPrimitiveClass(&quot;int&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. instanceof 연산자 기능 실행하기: isInstance&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;isInstance 메소드로 Class 객체의 타입을 확인할 수 있습니다. instanceof 연산자와 같은 기능을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 코드는 true를 반환합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630837966513&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try {
	Class&amp;lt;?&amp;gt; c = Class.forName(&quot;A&quot;);
	boolean b = c.isInstance(new A());
catch (ClassNotFoundException e) {
  // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 클래스의 멤버 메소드 알아내기: getDeclaredMethods&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플렉션의 가장 중요하고 기본적인 사용 중에 하나는 클래스에 정의된 메소드를 알아내는 것입니다. getDeclaredMethods 메소드는 클래스에 정의된 메소드에 대한 Method 배열을 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 사용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630838897944&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Method[] methods = c.getDeclaredMethods();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getDeclaredMethods 메소드의 내부 코드는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630838958278&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@CallerSensitive
public Method[] getDeclaredMethods() throws SecurityException {
	SecurityManager sm = System.getSecurityManager();
	if (sm != null) {
	    checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
	}
	return copyMethods(privateGetDeclaredMethods(false));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. 클래스의 생성자 알아내기: getDeclaredConstructors&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getDeclaredConstructors 메소드로 클래스에 정의된 생성자들을 알아낼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630838977628&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Constructor&amp;lt;?&amp;gt;[] constructors = c.getDeclaredConstructors();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;getDeclaredConstructors 메소드의 내부는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630838993435&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@CallerSensitive
public Constructor&amp;lt;?&amp;gt;[] getDeclaredConstructors() throws SecurityException {
  SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
      checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
  }
  return copyConstructors(privateGetDeclaredConstructors(false));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;7. 클래스의 멤버 필드 알아내기: getDeclaredFields&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getDeclaredFields 메소드로 클래스에 정의된 필드들을 알아낼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630839016565&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Field fieldlist[] = c.getDeclaredFields();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;getDeclaredFields 메소드의 내부는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630839026769&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@CallerSensitive
public Field[] getDeclaredFields() throws SecurityException {
  SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
      checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
  }
  return copyFields(privateGetDeclaredFields(false));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;8. 메소드 실행하기: invoke&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reflection을 통해 알아낸 Method 객체를 통해 메소드를 실행할 수 있습니다. 아래와 같이 invoke 메소드를 실행하면&amp;nbsp; 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630839558493&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try {
	Object[] arglist = new Object[2];
	arglist[0] = 0;
	arglist[1] = 1;

	Object retobj = methods[0].invoke(&quot;the object the underlying method is invoked from&quot;, arglist);
} catch (IllegalAccessException | InvocationTargetException e) {
	e.printStackTrace();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;invoke 메소드의 내부는 다음과 같이 정의되어 있습니다. 파라미터로 메소드를 호출하는 객체와 그 메소드의 파라미터를 받고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1630839688904&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@CallerSensitive
@ForceInline // to ensure Reflection.getCallerClass optimization
@HotSpotIntrinsicCandidate
public Object invoke(Object obj, Object... args)
    throws IllegalAccessException, IllegalArgumentException,
       InvocationTargetException
{
    if (!override) {
        Class&amp;lt;?&amp;gt; caller = Reflection.getCallerClass();
        checkAccess(caller, clazz,
                    Modifier.isStatic(modifiers) ? null : obj.getClass(),
                    modifiers);
    }
    MethodAccessor ma = methodAccessor;             // read volatile
    if (ma == null) {
        ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;9. 새로운 객체 생성하기: newInstance &lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getDeclaredConstructors를 통해 Constructor 객체를 얻어낼 수 있었습니다. Constructor 객체의 newInstance 메소드를 통해 새로운 객체를 생성할 수 있습니다. 파라미터로는 생성자의 파라미터를 넘겨줄 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630840235658&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Constructor&amp;lt;?&amp;gt;[] constructors = c.getDeclaredConstructors();

try {
    Objects obj = (Objects) constructors[0].newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
    e.printStackTrace();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;newInstance 메소드의 내부는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1630840253444&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@CallerSensitive
@ForceInline // to ensure Reflection.getCallerClass optimization
public T newInstance(Object ... initargs)
    throws InstantiationException, IllegalAccessException,
           IllegalArgumentException, InvocationTargetException
{
    if (!override) {
        Class&amp;lt;?&amp;gt; caller = Reflection.getCallerClass();
        checkAccess(caller, clazz, clazz, modifiers);
    }
    if ((clazz.getModifiers() &amp;amp; Modifier.ENUM) != 0)
        throw new IllegalArgumentException(&quot;Cannot reflectively create enum objects&quot;);
    ConstructorAccessor ca = constructorAccessor;   // read volatile
    if (ca == null) {
        ca = acquireConstructorAccessor();
    }
    @SuppressWarnings(&quot;unchecked&quot;)
    T inst = (T) ca.newInstance(initargs);
    return inst;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;느낀 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class 객체를 얻어내어 멤버 필드, 메소드, 생성자에 대한 정보를 알아내고 조작하는 방법에 대해 알아보았습니다. 코드를 직접 보고 나니 Java에서 Reflection 기능을 어떻게 제공하는지 알 수 있었습니다. 또, 이를 통해 빌더 툴이나 프레임워크에서 클래스의 정보를 알아내어 클래스의 생명주기를 관리하는 데에 활용될 수 있다는 것을 알게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>Java</category>
      <category>Reflection</category>
      <category>리플렉션</category>
      <category>자바</category>
      <author>림 림</author>
      <guid isPermaLink="true">https://limdevbasic.tistory.com/25</guid>
      <comments>https://limdevbasic.tistory.com/25#entry25comment</comments>
      <pubDate>Sun, 5 Sep 2021 20:19:01 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 동일성(Identity)와 동등성(Equality), 그리고 hashCode와 equals</title>
      <link>https://limdevbasic.tistory.com/24</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;클래스의 객체를 비교할 때, 동일성을 비교할 것인지 동등성을 비교할 것인지를 명확하게 해야 할 때가 있습니다. 그렇다면 동일성과 동등성이란 무엇일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;동일성(Identity)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 객체의 동일성을 비교했을 때 같다는 것은, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;실제 객체가 같다&lt;/span&gt;는 것입니다. 두 객체가 가지고 있는 값이 같을 뿐만아니라 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;힙 메모리 상에서 같은 주소에 위치&lt;/span&gt;해야 합니다. 두 객체가 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;물리적&lt;/span&gt;으로 같은지를 비교하는 셈입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, 동일한 객체는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;같은 해시 코드 값&lt;/span&gt;을 가집니다. &lt;br /&gt;해시 코드 값이란 모든 객체가 가지고 있는 고유한 값으로, 보통 객체가 위치한 메모리 주소에 특정 함수를 적용한 결과값을 나타냅니다.&lt;br /&gt;해시 코드 값은 Object 클래스의 멤버 메소드인 hashCode()로 얻을 수 있습니다. 모든 객체는 Object 클래스의 서브클래스이기 때문에, 모든 객체에서 상위 클래스인 Object 클래스의 hashCode() 메소드를 호출할 수 있습니다. 두 객체의 해시 코드 값을 비교했을 때 같다면 두 객체는 동일성이 같은 객체입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 객체의 해시 코드 값을 비교하는 방법보다 간단한 방법은 ==연산자를 활용하는 것입니다. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;==연산자로 비교했을 때 true&lt;/span&gt;라면 동일성이 같은 객체입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;동등성(Equality)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 객체의 동등성을 비교했을 때 같다는 것은, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;객체가 가지고 있는 값이 같다&lt;/span&gt;는 것입니다. 즉, 객체의 멤버 필드가 가리키는 값들이 서로 같다는 것을 의미합니다. 두 객체가 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;논리적&lt;/span&gt;으로 같은지를 비교하는 셈입니다. 동등성이 같은 객체는 동일성이 같을 수도 있고 다를 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서 두 객체의 동등성을 비교할 때는 주로 Object 클래스의 equals() 메소드를 오버라이딩 하여 활용합니다. Object 클래스의 equals() 메소드는 다음과 같이 작성되어 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1629781677113&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public boolean equals(Object obj) {
	return (this == obj);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수로 전달된 객체를 ==연산자로 비교하여 결과값을 리턴합니다. equals() 메소드를 오버라이딩 하지 않고 사용하면, 동일성을 비교하게 됩니다. 따라서 equals() 메소드의 내부를 this와 obj의 멤버 필드의 값이 같은지를 비교한 결과를 리턴하도록 오버라이딩하면 동등성을 비교할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;hashCode()와 equals()&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hashCode()와 equals()는 모두 Object 클래스의 멤버 메소드입니다. 더 자세한 내용은 아래의 포스팅을 참고하시면 좋습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1629782336351&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java] Object 클래스&quot; data-og-description=&quot;자바를 배울 때 모든 클래스는 Object 클래스를 상속받는 하위 클래스라고 배웠습니다. Object 클래스에 대해 더 자세히 공부해보았습니다. Index Object 클래스의 전체 코드 package import constructor getClass&quot; data-og-host=&quot;limdevbasic.tistory.com&quot; data-og-source-url=&quot;https://limdevbasic.tistory.com/23&quot; data-og-url=&quot;https://limdevbasic.tistory.com/23&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/towPS/hyLmL2N5FU/TFJl46vQOqwwBXTg37KMbk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bUqZK3/hyLmPRFXT0/P9FVXaWN9BSbglGDywFga1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/OVW8Q/hyLmPqClem/XC0OIxIf53Odp0fGEFINn0/img.jpg?width=280&amp;amp;height=280&amp;amp;face=0_0_280_280&quot;&gt;&lt;a href=&quot;https://limdevbasic.tistory.com/23&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://limdevbasic.tistory.com/23&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/towPS/hyLmL2N5FU/TFJl46vQOqwwBXTg37KMbk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bUqZK3/hyLmPRFXT0/P9FVXaWN9BSbglGDywFga1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/OVW8Q/hyLmPqClem/XC0OIxIf53Odp0fGEFINn0/img.jpg?width=280&amp;amp;height=280&amp;amp;face=0_0_280_280');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java] Object 클래스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;자바를 배울 때 모든 클래스는 Object 클래스를 상속받는 하위 클래스라고 배웠습니다. Object 클래스에 대해 더 자세히 공부해보았습니다. Index Object 클래스의 전체 코드 package import constructor getClass&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;limdevbasic.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>Equality</category>
      <category>Equals</category>
      <category>HashCode</category>
      <category>Identity</category>
      <category>Java</category>
      <category>동등성</category>
      <category>동일성</category>
      <category>자바</category>
      <author>림 림</author>
      <guid isPermaLink="true">https://limdevbasic.tistory.com/24</guid>
      <comments>https://limdevbasic.tistory.com/24#entry24comment</comments>
      <pubDate>Tue, 24 Aug 2021 14:20:14 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Object 클래스</title>
      <link>https://limdevbasic.tistory.com/23</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자바를 배울 때 모든 클래스는 Object 클래스를 상속받는 하위 클래스라고 배웠습니다. Object 클래스에 대해 더 자세히 공부해보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Index&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Object 클래스의 전체 코드&lt;/li&gt;
&lt;li&gt;package&lt;/li&gt;
&lt;li&gt;import&lt;/li&gt;
&lt;li&gt;constructor&lt;/li&gt;
&lt;li&gt;getClass()&lt;/li&gt;
&lt;li&gt;hashCode()&lt;/li&gt;
&lt;li&gt;equals()&lt;/li&gt;
&lt;li&gt;clone()&lt;/li&gt;
&lt;li&gt;toString()&lt;/li&gt;
&lt;li&gt;notify(), notifyAll()&lt;/li&gt;
&lt;li&gt;wait()&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Object 클래스의 전체 코드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 11의 Object 클래스의 코드를 보면 다음과 같습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package java.lang;

import jdk.internal.HotSpotIntrinsicCandidate;

public class Object {

  private static native void registerNatives();
  static {
      registerNatives();
  }

  @HotSpotIntrinsicCandidate
  public Object() {}

  @HotSpotIntrinsicCandidate
  public final native Class&amp;lt;?&amp;gt; getClass();

  @HotSpotIntrinsicCandidate
  public native int hashCode();

  public boolean equals(Object obj) {
      return (this == obj);
  }

  @HotSpotIntrinsicCandidate
  protected native Object clone() throws CloneNotSupportedException;

  public String toString() {
      return getClass().getName() + &quot;@&quot; + Integer.toHexString(hashCode());
  }

  @HotSpotIntrinsicCandidate
  public final native void notify();


  @HotSpotIntrinsicCandidate
  public final native void notifyAll();

  public final void wait() throws InterruptedException {
        wait(0L);
  }

  public final native void wait(long timeoutMillis) throws InterruptedException;

  public final void wait(long timeoutMillis, int nanos) throws InterruptedException {
    if (timeoutMillis &amp;lt; 0) {
    	throw new IllegalArgumentException(&quot;timeoutMillis value is negative&quot;);
    }

    if (nanos &amp;lt; 0 || nanos &amp;gt; 999999) {
    	throw new IllegalArgumentException(&quot;nanosecond timeout value out of range&quot;);
    }

    if (nanos &amp;gt; 0) {
    	timeoutMillis++;
    }
    
    wait(timeoutMillis);
  }


  @Deprecated(since=&quot;9&quot;)
  protected void finalize() throws Throwable { }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. package&lt;/h3&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;package java.lang;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Object 클래스는 java.lang 패키지에 위치하고 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. import&lt;/h3&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;import jdk.internal.HotSpotIntrinsicCandidate;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jdk.internal 패키지에 있는 HotSpotIntrinsicCandidate 어노테이션을 import하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Object 클래스 내부 코드를 보면, 멤버 변수가 없고 몇몇 멤버 메소드에 @HotSpotIntrinsicCandidate 어노테이션이 붙어있는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@HotSpotIntrinsicCandidate &lt;/b&gt;어노테이션이 붙은 메소드는 HotSpot VM에 내재화(intrinsify)될 수도 있고 아닐 수도 있다는 것을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HotSpot은 Java 11에서 사용하는 JVM 구현체입니다. 아래의 링크에서 더 자세한 내용을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&quot;&gt;Java Virtual Machine Guide&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1628412870413&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Java Virtual Machine Guide&quot; data-og-description=&quot; &quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&quot; data-og-url=&quot;https://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/en/java/javase/11/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651-CB6475019281&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Java Virtual Machine Guide&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VM에 내재화된다는 것은 성능 향상을 위해 컴파일러가 메소드를 인라인 코드로 대체한다는 것입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. constructor&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;  @HotSpotIntrinsicCandidate
  public Object() {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Object 클래스에는 기본 생성자가 하나 있습니다. Object 클래스는 멤버 변수가 없기 때문에 생성자의 매개변수도 없고 바디부분에서 처리하는 코드도 없습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. getClass()&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;  @HotSpotIntrinsicCandidate
  public final native Class&amp;lt;?&amp;gt; getClass();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getClass() 메소드는 Class 타입의 객체를 리턴합니다. 리턴된 Class 타입의 객체는 getClass()를 호출한 객체가 런타임에서 어떤 클래스의 객체인지를 표현하는 객체입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. hashCode()&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;  @HotSpotIntrinsicCandidate
  public native int hashCode();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hashCode() 메소드는 객체의 고유한 해시 코드 값을 리턴합니다. 해시 코드 값은 주로 객체의 메모리 주소에 해시 함수를 적용한 값입니다.(항상 그런 것은 아닙니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hashCode() 메소드는 java.util 패키지의 HashMap이나 HashSet과 같이 해시 테이블을 구현하는 데에 사용됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. equals()&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;  public boolean equals(Object obj) {
      return (this == obj);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;equals() 메소드는 이 메소드를 호출하는 객체와 매개변수로 전달되는 객체가 같은 객체인지 확인하는 객체입니다. == 연산자로 객체를 비교하기 때문에 두 객체가 참조하는 것이 같을 경우에 true를 리턴합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 잠깐,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hashCode()와 equals() 는 특별한 관계를 가집니다. 보편적으로 다음과 같이 사용됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;equals() 메소드로 객체를 비교하는 데에 사용된 정보가 변경되지 않았다면(오버라이딩 하지 않았다면), 한번의 실행에서 hashCode() 메소드는 일관적으로 같은 해시 코드 값을 반환해야 한다.(다른 실행에서는 값이 달라질 수도 있다.)&lt;/li&gt;
&lt;li&gt;equals() 메소드로 비교했을 때 같다면 hashCode() 메소드로 같은 해시 코드 값을 반환해야 한다.&lt;/li&gt;
&lt;li&gt;equals() 메소드로 비교했을 때 다르다면 hashCode() 꼭 메소드로 다른 해시 코드 값을 반환해야하는 것은 아니다. 그치만 해시 테이블에서 사용할 경우에는 다른 해시 코드 값을 반환해야 해시 값이 충돌하는 일이 적어지기 때문에 성능을 향상시킬 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 equals() 메소드를 객체가 물리적으로 같은 메모리에 있는 값을 참조하는지 비교하기 위해 사용하는 것이 아니라 객체의 값이 논리적으로 같은지 사용하기 위해 오버라이딩했다면, hashCode() 메소드도 적절하게 오버라이딩하는 것이 좋습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. clone()&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;  @HotSpotIntrinsicCandidate
  protected native Object clone() throws CloneNotSupportedException;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clone() 메소드는 객체의 복사본 객체를 생성하고 반환합니다. 여기서 복사된 객체는 '같은 클래스 타입인 객체'를 말합니다. clone() 메소드를 호출하는 객체의 클래스는 Cloneable 인터페이스를 구현해야 합니다. 클래스가 Cloneable 인터페이스를 구현하지 않으면 CloneNotSupportedException 예외가 발생합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;x.clone() != x&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 식은 true입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;x.clone().getClass() == x.getClass()&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 식은 true일 수도 있고 false일 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관습적으로 clone() 메소드는 객체의 슈퍼 클래스의 clone()을 호출하여 얻어진 객체를 반환합니다. 클래스와 그 슈퍼클래스(Object 클래스 제외)가 이 컨벤션을 따른다면 이 식이 true가 됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;x.clone().equals(x)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 식은 true일 수도 있고 false일 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관습적으로 clone() 메소드를 통해 반환된 클래스는 clone() 메소드를 호출한 객체와 독립적입니다. 객체와 복사된 객체가 독립성을 유지하려면 객체의 슈퍼 클래스의 clone()을 호출하여 얻어진 객체를 리턴하기 전에 하나 이상의 필드가 수정되어야 합니다. 전형적으로 가변 객체는 복제되고 그에 대한 참조를 복사된 객체의 참조로 대체합니다. 만약 클래스의 필드가 모두 기본 자료형이고 불변 객체만을 참조한다면, 슈퍼 클래스의 clone() 메소드로 얻어진 객체의 필드를 수정하지 않아도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. toString()&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;  public String toString() {
      return getClass().getName() + &quot;@&quot; + Integer.toHexString(hashCode());
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;toString() 메소드는 객체를 표현하는 문자열을 리턴합니다. 문자열은 사람이 읽기 쉽고 간결해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Object 클래스의 toString() 메소드는 클래스의 이름과 '@'문자와 16진수로 표현한 객체의 해시 코드를 붙인 문자열을 반환합니다. 그래서 Object 클래스의 하위 클래스는 toString() 메소드를 적절하게 오버라이딩해서 활용하는 것을 추천합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. notify(), notifyAll()&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;  @HotSpotIntrinsicCandidate
  public final native void notify();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;notify() 메소드는 객체 모니터에서 대기 상태에 있는 스레드 하나를 깨웁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 객체들은 객체 모니터를 가지는데, 객체 모니터는 객체에 여러 스레드들이 동시에 접근하는 것을 막아주는 역할을 합니다. 객체 모니터에는 객체를 사용하려고 하는 스레드들이 대기하고 있고, 이 스레드들은 뒤에 나올 wait()메소드에 의해 대기 상태로 들어간 것입니다. 객체 모니터를 가지고있는 스레드는 이 객체에 대한 lock을 걸 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;notify()에 의해 깨어난 스레드는 현재 이 객체 모니터를 가지고 있는 스레드가 객체에 대한 lock을 풀 때 까지 기다려야 합니다. notify() 메소드는 이 객체 모니터를 가지고 있는 스레드에서만 호출되어야 합니다. 만약 현재 스레드가 객체 모니터의 소유자가 아니라면 IllegalMonitorStateException 예외가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드가 객체 모니터의 소유자가 되는 방법은 다음 세 가지가 있습니다. 동시에 하나의 스레드만 객체 모니터를 소유할 수 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 동기화된 인스턴스 메소드를 실행하기&lt;/li&gt;
&lt;li&gt;객체의 synchronized 문 안의 body를 실행하기&lt;/li&gt;
&lt;li&gt;Class 타입의 객체에서 synchronized static 메소드를 실행하기&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;  @HotSpotIntrinsicCandidate
  public final native void notifyAll();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;notifyAll() 메소드는 객체 모니터에서 대기 상태에 있는 모든 스레드를 깨웁니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11. wait()&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;  public final void wait() throws InterruptedException {
        wait(0L);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wait() 메소드는 현재 스레드가 notify() 메소드에 의해 깨워질 때까지 대기 상태로 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wait() 메소드도 객체 모니터의 소유자인 스레드에서 호출되어야 합니다. 만약 아니라면 IllegalMonitorStateException 예외가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;    public final native void wait(long timeoutMillis) throws InterruptedException;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wait(long timeoutMills) 메소드는 일정 시간이 경과할 때까지 스레드를 대기 상태로 만듭니다. 만약 timeoutMills가 0이라면 스레드가 깨워질 때까지 대기 상태로 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;timeoutMills가 음수면 IllegalArgumentException 예외가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드가 객체 모니터의 소유자가 아니면 IllegalMonitorStateException 예외가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 현재 스레드가 대기 상태로 들어가기 전이거나 대기 상태인데 다른 스레드에 의해 인터럽트되어 중단된 경우InterruptedException 예외가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;    public final void wait(long timeoutMillis, int nanos) throws InterruptedException {
      if (timeoutMillis &amp;lt; 0) {
          throw new IllegalArgumentException(&quot;timeoutMillis value is negative&quot;);
      }

      if (nanos &amp;lt; 0 || nanos &amp;gt; 999999) {
          throw new IllegalArgumentException(
                              &quot;nanosecond timeout value out of range&quot;);
      }

      if (nanos &amp;gt; 0) {
          timeoutMillis++;
      }

      wait(timeoutMillis);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wait(long timeoutMills, int nanos) 메소드는 일정 시간이 경과할 때까지 현재 스레드를 대기 상태로 만듭니다. 이 대기 상태에서는 객체에 대한 모든 동기화된 요청을 처리할 수 없습니다. wait 메소드를 호출한 객체의 lock만 풀고 대기 상태에 들어가며, 다른 객체에 대한 lock은 풀리지 않습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;12. finalize()&lt;/h3&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;    @Deprecated(since=&quot;9&quot;)
    protected void finalize() throws Throwable { }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 메소드는 Java 9부터 deprecated되어 사용되지 않는다. 이 객체에 대한 참조가 없을 경우에 가비지 컬렉터에서 호출되는 메소드입니다.&lt;/p&gt;</description>
      <category>Java</category>
      <category>Equal</category>
      <category>hash code</category>
      <category>Java</category>
      <category>object class</category>
      <category>ToString</category>
      <category>자바</category>
      <category>최상위 클래스</category>
      <author>림 림</author>
      <guid isPermaLink="true">https://limdevbasic.tistory.com/23</guid>
      <comments>https://limdevbasic.tistory.com/23#entry23comment</comments>
      <pubDate>Sun, 8 Aug 2021 18:02:00 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Oracle Java API 버그 제보하기</title>
      <link>https://limdevbasic.tistory.com/22</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;작년에 Java 11의 java.net패키지에 있는 HttpURLConnection 클래스 내부의 코드를 읽어보다가 Java Doc에 작은 오타가 있는 것을 발견했습니다. 그래서 Oracle Java SE 커뮤니티의 Bug Report를 활용해서 오타를 제보했었는데, 그 경험을 공유하기 위해 글을 작성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Index&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;버그 제보 결과&lt;/li&gt;
&lt;li&gt;버그 제보 방법&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 버그 제보 결과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HttpURLConnection클래스에 getResponseCode() 메소드의 Java Doc에 'If we can't a status-line then re-throw any exception' 이라는 문구가 있었습니다. 'can't'와 'a' 사이에 동사가 빠져있는 오타가 있었고, 이 자리에 'find'가 들어가면 적절할 것이라고 판단했습니다. 비록 개발하는 데에는 문제가 없는 작은 오타지만 더 완벽하고 나은 Java 플랫폼을 위해 버그를 제보해야겠다고 생각했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 제보했던 오타는 &lt;a href=&quot;https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8255675&quot;&gt;https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8255675&lt;/a&gt;&amp;nbsp; 에서 확인할 수 있습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1628401600806&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Bug ID: JDK-8255675 Typo in java.net.HttpURLConnection&quot; data-og-description=&quot;&quot; data-og-host=&quot;bugs.java.com&quot; data-og-source-url=&quot;https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8255675&quot; data-og-url=&quot;https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8255675&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8255675&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8255675&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Bug ID: JDK-8255675 Typo in java.net.HttpURLConnection&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;bugs.java.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;1708&quot; data-filename=&quot;스크린샷 2021-08-08 오후 2.50.11.png&quot; width=&quot;530&quot; height=&quot;765&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kGfoV/btrbvw1N8UJ/1eTHx1yj9X2VzpTYcjrbo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kGfoV/btrbvw1N8UJ/1eTHx1yj9X2VzpTYcjrbo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kGfoV/btrbvw1N8UJ/1eTHx1yj9X2VzpTYcjrbo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkGfoV%2Fbtrbvw1N8UJ%2F1eTHx1yj9X2VzpTYcjrbo0%2Fimg.png&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;1708&quot; data-filename=&quot;스크린샷 2021-08-08 오후 2.50.11.png&quot; width=&quot;530&quot; height=&quot;765&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Description란에 설명을 작성했고, Comments에 두개의 댓글이 달렸습니다. 하나의 댓글은 더 자연스러운 영어로 설명을 작성해준 댓글이었고, 다른 하나는 수정사항이 반영된 OpenJDK 깃허브의 링크가 있는 댓글이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 변경사항은 JDK 16에 반영되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 버그 제보 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 버그를 제보하는 방법에 대해 알려드리겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버그를 제보하기 전에 두 가지를 만족하는지 확인해야 합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;버그가 최신 버전의 Java SE에 있어야 합니다.&lt;/li&gt;
&lt;li&gt;Bug Database에 같은 내용의 버그가 이미 제보되었는지 확인해야 합니다. 아래의 버그 데이터베이스 링크에서 키워드와 버그 번호로 버그를 검색할 수 있습니다. &lt;a href=&quot;https://bugs.java.com/bugdatabase/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://bugs.java.com/bugdatabase/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;figure id=&quot;og_1628402239964&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Bug Database&quot; data-og-description=&quot;Report an Issue If you discover an issue with the JDK, please start by searching the Bug Database to find out if that issue has been reported and fixed already. Once you confirm that the issue you discovered is new, please report it here. In your report, p&quot; data-og-host=&quot;bugs.java.com&quot; data-og-source-url=&quot;https://bugs.java.com/bugdatabase/&quot; data-og-url=&quot;https://bugs.java.com/bugdatabase/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://bugs.java.com/bugdatabase/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://bugs.java.com/bugdatabase/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Bug Database&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Report an Issue If you discover an issue with the JDK, please start by searching the Bug Database to find out if that issue has been reported and fixed already. Once you confirm that the issue you discovered is new, please report it here. In your report, p&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;bugs.java.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 두 가지 사항을 만족한다면, 아래의 링크에서 버그를 제보할 수 있습니다. &lt;a href=&quot;https://bugreport.java.com/bugreport/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://bugreport.java.com/bugreport/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1628402107727&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Bug Report&quot; data-og-description=&quot;Report a Bug or Request a Feature&quot; data-og-host=&quot;bugreport.java.com&quot; data-og-source-url=&quot;https://bugreport.java.com/bugreport/&quot; data-og-url=&quot;https://bugreport.java.com/bugreport/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://bugreport.java.com/bugreport/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://bugreport.java.com/bugreport/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Bug Report&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Report a Bug or Request a Feature&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;bugreport.java.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Start a New Report 버튼을 누릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 버그의 종류, 버그를 발견한 운영체제 환경, Java 버전 등을 선택합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 제목과 함께 버그에 대한 설명을 영어로 작성하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다 작성하셨다면, 버그 제보를 완료하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버그를 제보하고 나면 OpenJDK 프로젝트에 반영이 되고, 추후에 다음 버전에서 반영될 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>오라클 자바</category>
      <category>자바 버그</category>
      <category>자바 오타</category>
      <author>림 림</author>
      <guid isPermaLink="true">https://limdevbasic.tistory.com/22</guid>
      <comments>https://limdevbasic.tistory.com/22#entry22comment</comments>
      <pubDate>Sun, 8 Aug 2021 15:04:09 +0900</pubDate>
    </item>
    <item>
      <title>[Java] JPMS와 Module</title>
      <link>https://limdevbasic.tistory.com/21</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;package에 대해 공부하던 중, module이라는 개념을 새롭게 접하게 되었습니다. module이 무엇인지, 언제 생겨났는지, 언제 쓰이는지에 대해 공부해보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Index&lt;/i&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPMS(Java 9 Platform Module System)&lt;/li&gt;
&lt;li&gt;JPMS 이전&lt;/li&gt;
&lt;li&gt;JPMS의 목표&lt;/li&gt;
&lt;li&gt;Module&lt;/li&gt;
&lt;li&gt;Module Example&lt;/li&gt;
&lt;li&gt;Module 선언하기&lt;/li&gt;
&lt;li&gt;Module Keywords&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. JPMS(Java 9 Platform Module System)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle Java 9에서 JPMS와 함께 Module이 소개되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Module은 OpenJDK의 Jigsaw 프로젝트의 결과물입니다. Jigsaw 프로젝트에 대한 자세한 내용은 아래의 링크에서 참고할 수 있습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1628347316709&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Project Jigsaw&quot; data-og-description=&quot;Project Jigsaw The primary goals of this Project were to: Make it easier for developers to construct and maintain libraries and large applications; Improve the security and maintainability of Java&amp;nbsp;SE Platform Implementations in general, and the JDK in par&quot; data-og-host=&quot;openjdk.java.net&quot; data-og-source-url=&quot;http://openjdk.java.net/projects/jigsaw/&quot; data-og-url=&quot;http://openjdk.java.net/projects/jigsaw/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;http://openjdk.java.net/projects/jigsaw/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://openjdk.java.net/projects/jigsaw/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Project Jigsaw&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Project Jigsaw The primary goals of this Project were to: Make it easier for developers to construct and maintain libraries and large applications; Improve the security and maintainability of Java&amp;nbsp;SE Platform Implementations in general, and the JDK in par&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;openjdk.java.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 방식의 장점부터 이야기해보자면, 개발자가 소프트웨어 시스템(특히 대규모 시스템)을 개발, 유지 보수, 그리고 발전시킬 때 생산성을 높일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. JPMS 이전&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java SE 플랫폼은 1995년부터 존재해왔습니다. 개발자들은 IoT나 임베디드 디바이스 등을 위한 작은 애플리케이션부터 비즈니스를 위한 대규모의 시스템까지의 다양한 시스템을 개발하기 위해 Java SE를 사용해왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때까지 Java 플랫폼은 하나의 시스템이 전체를 이루는 모놀리틱 솔루션으로 제공되었고, Open JDK 및 Oracle은 Java SE를 모듈화하기 위해 오랜 시간동안 노력했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 2005년에 &lt;i&gt;JSR 277: Java Module System&lt;/i&gt;이 최초로 Java 7을 대상으로 소개되었습니다. 그리고 나중에 Java 8을 대상으로 하는&amp;nbsp;&lt;i&gt;JSR 376: Java Platform Module System&lt;/i&gt;으로 대체되었습니다. 그리고 Java 9에서부터 정식으로 모듈 시스템이 도입되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. JPMS의 목표&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서 JPMS를 통해 이루고자 하는 목표는 다음과 같습니다. JPMS의 목표를 이해하기 위해서는 모듈이 무엇인지 알아야 합니다. 뒤에서 더 자세하게 다루고, 지금은 '패키지의 묶음' 정도로 이해하시면 될 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;1. Reliable configuration(신뢰적인 구성)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈은 서로 의존 관계를 가질 수 있는데, 모듈 간의 의존성을 명시적으로 선언할 수 있는 매커니즘을 제공합니다. 이 매커니즘을 통해 모든 모듈 중에서 시스템에 필요한 모듈만을 고를 수 있습니다. 설정된 의존성은 컴파일 시와 런타임 시에 모두 인식됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;2. Strong encapsulation(강력한 캡슐화)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 내에 있는 패키지를 다른 모듈이 접근할 수 없습니다. 모듈 configuration에서 명시적으로 export한 패키지에 대해서만 다른 모듈이 접근할 수 있습니다. 그리고 다른 모듈은 그 패키지를 명시적으로 사용한다고 선언해야 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈의 캡슐화는 잠재적인 공격자가 클래스에 접근하는 것을 막아주기 때문에 플랫폼의 보안을 향상시킵니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Scalable Java platform(확장 가능한 Java 플랫폼)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에는 Java 플랫폼이 방대한 패키지들로 구성된 모놀리틱 플랫폼이었기 때문에, 시스템을 개발, 유지 보수, 발전시키는 데에 어려움이 있었습니다. 이제는 플랫폼이 여러 모듈로 모듈화되어 애플리케이션에 필요한 모듈들로만 런타임을 구성할 수 있습니다. 이를 통해 런타임의 크기를 줄일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Greater platform integrity(더 나은 플랫폼 무결성)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 9 이전에는 Java API 중에 사용하라는 의미가 아니었던 클래스들을 &amp;nbsp;애플리케이션에서 사용할 수 있었습니다. 이제는 캡슐화를 통해 이런 내부 API들은 Java 플랫폼을 사용하는 애플리케이션에서는 숨겨지고 사용할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. Improved performance(향상된 성능)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM은 애플리케이션의 성능 향상을 위해 다양한 최적화 기법을 사용합니다. 이런 기법들은 모듈 간의 의존성을 컴파일 단계에 미리 알고있을 때 더 효과적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Module&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 모듈이란 무엇일까요? 모듈은 패키지의 상위 집합체입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;312&quot; width=&quot;379&quot; height=&quot;218&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tN50J/btrbvaR7BqJ/ZKRNVGLuJRe2bART1tt6W1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tN50J/btrbvaR7BqJ/ZKRNVGLuJRe2bART1tt6W1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tN50J/btrbvaR7BqJ/ZKRNVGLuJRe2bART1tt6W1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtN50J%2FbtrbvaR7BqJ%2FZKRNVGLuJRe2bART1tt6W1%2Fimg.png&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;312&quot; width=&quot;379&quot; height=&quot;218&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈은 고유한 이름을 가지고, 서로 관련있는&amp;nbsp;&lt;b&gt;패키지&lt;/b&gt;들,&amp;nbsp;&lt;b&gt;리소스&lt;/b&gt;(이미지, XML 파일 등),&amp;nbsp;&lt;b&gt;module descriptor&lt;/b&gt;로 구성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모듈의 특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고유한 모듈명을 가진다.&lt;/li&gt;
&lt;li&gt;모듈간 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;의존성&lt;/span&gt;을 가진다.&lt;/li&gt;
&lt;li&gt;모듈간 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;캡슐화&lt;/span&gt;가 적용된다.&lt;/li&gt;
&lt;li&gt;service provider가 될 수 있다.&lt;/li&gt;
&lt;li&gt;service consumer가 될 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. Module Example&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Java 11 모듈&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle JDK 11의 Contents/Home 디렉토리를 보면 다음과 같이 java. 와 jdk. 로 시작하는 수많은 모듈들이 있습니다. (너무 많아서 공백으로 구분지었습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;java.base&lt;/span&gt; java.compiler java.datatransfer java.desktop java.instrument java.logging java.management java.management.rmi java.naming java.net.http java.prefs java.rmi java.scripting java.se java.security.jgss java.security.sasl java.smartcardio java.sql java.sql.rowset java.transaction.xa java.xml java.xml.crypto jdk.accessibility jdk.aot jdk.attach jdk.charsets jdk.compiler jdk.crypto.cryptoki &lt;a href=&quot;http://jdk.crypto.ec/&quot;&gt;j&lt;/a&gt;dk.crypto.ec jdk.dynalink jdk.editpad jdk.hotspot.agent jdk.httpserver jdk.internal.ed jdk.internal.jvmstat jdk.internal.le jdk.internal.opt &lt;a href=&quot;http://jdk.internal.vm.ci/&quot;&gt;j&lt;/a&gt;dk.internal.vm.ci jdk.internal.vm.compiler jdk.internal.vm.compiler.management jdk.jartool jdk.javadoc jdk.jcmd jdk.jconsole jdk.jdeps jdk.jdi jdk.jdwp.agent jdk.jfr jdk.jlink jdk.jshell jdk.jsobject jdk.jstatd jdk.localedata jdk.management jdk.management.agent jdk.management.jfr jdk.naming.dns jdk.naming.ldap jdk.naming.rmi jdk.net jdk.pack jdk.rmic jdk.scripting.nashorn jdk.scripting.nashorn.shell jdk.sctp jdk.security.auth jdk.security.jgss jdk.unsupported jdk.unsupported.desktop jdk.xml.dom jdk.zipfs&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;java.base 모듈&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 수많은 모듈들 중에 제일 중요한 모듈은 java.base 모듈입니다. 저와 같은 학생 개발자들이 흔히 아는 java.lang, java.util 등의 패키지들이 이 java.base 모듈에 있습니다. 오라클 Docs의 설명에 따르면 java.base 모듈은 Java SE 플랫폼의 기본 API들을 정의한 모듈이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 모듈들은 서로 의존 관계를 가질 수 있다고 했습니다. java.base 모듈은 기본적인 API들이 있는 모듈인 만큼 다른 모듈에 의존하지 않고, 다른 모듈들은 아래의 그래프와 같이 명시적 또는 암묵적으로 java.base 모듈에 의존합니다. 명시적으로 의존한다는 것은 module configuration 파일에 다른 모듈을 의존한다고 명시했다는 뜻이고, 암묵적으로 의존한다는 것은 의존하는 모듈이 의존하는 모듈을 직접 명시하지 않아도 자동으로 의존되게끔 설정되었을 경우를 말합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;224&quot; width=&quot;985&quot; height=&quot;173&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnbBIr/btrbxrshStV/qBCKWxS8QhKnE5zEtzpTa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnbBIr/btrbxrshStV/qBCKWxS8QhKnE5zEtzpTa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnbBIr/btrbxrshStV/qBCKWxS8QhKnE5zEtzpTa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnbBIr%2FbtrbxrshStV%2FqBCKWxS8QhKnE5zEtzpTa0%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;224&quot; width=&quot;985&quot; height=&quot;173&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 모듈은 패키지, 리소스, module descriptor로 구성되었다고 했습니다. java.base 모듈은 아래 사진과 같이 7개의 패키지들과 module-info.class 라는 파일의 module descriptor로 구성되어 있습니다. module-info.class 파일에 모듈이 선언되어 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;370&quot; width=&quot;471&quot; height=&quot;258&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q8xnc/btrbrVnRIps/46v6Qp5vV81UkwkPj4Tcv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q8xnc/btrbrVnRIps/46v6Qp5vV81UkwkPj4Tcv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q8xnc/btrbrVnRIps/46v6Qp5vV81UkwkPj4Tcv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ8xnc%2FbtrbrVnRIps%2F46v6Qp5vV81UkwkPj4Tcv1%2Fimg.png&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;370&quot; width=&quot;471&quot; height=&quot;258&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. Module 선언하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;module descriptor&lt;/b&gt;는 모듈의 정보를 담는 메타데이터로, 모듈을 정의하고 모듈의 &lt;b&gt;의존성&lt;/b&gt;과 내보내거나 사용하는 &lt;b&gt;패키지&lt;/b&gt;들, 제공하거나 소비하는 &lt;b&gt;서비스&lt;/b&gt;들을 명시하는 곳입니다. module-info.java 라는 이름의 파일을 컴파일한 module-info.class 파일이 바로 module descriptor입니다. 이 module descriptor는 최상위 폴더에 위치합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;module-info.java 파일에 module 키워드를 사용하여 모듈을 선언할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628349099988&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module modulename {
	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;body 부분은 비워도 되고, exports, uses 등의 다양한 키워드들로 모듈 의존성, 패키지, 서비스를 명시할 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. Module Keywords&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 선언한 module의 body 부분에 스이는 keyword에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. requires&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 모듈은 의존 관계를 가질 경우 반드시 의존성을 명시해야 합니다. requires 키워드는 이 모듈이 의존하고 있는 다른 모듈을 명시할 때 쓰는 키워드입니다. 모듈 A가 모듈 B를 requires한다면, 모듈 A는 모듈 B를 읽고, 모듈 B는 모듈 A에게 읽혀지는 관계라고 할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1628349279209&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;requires modulename;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;requires static 키워드를 통해 optional dependency를 선언할 수 있다. optional depency란, 컴파일 시에는 모듈을 필요로 하지만 런타임 시에는 선택적인 의존성을 말합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628349297065&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;requires static modulename;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. requires transitive&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;requires transitive 키워드로 의존성을 선언하면, 이 모듈을 의존하는 다른 모듈들도 이 키워드로 선언한 모듈들을 읽을 수 있습니다. 이것을 implied readability라고 합니다. 모듈 A에 requires transitive 키워드로 모듈 B를 선언하면, 모듈 A를 읽는 다른 모듈들도 모듈 B를 암묵적으로 읽을 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628349343494&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;requires transitive modulename;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. exports, exports-to&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;exports 키워드는 다른 모듈의 코드에서 접근할 수 있는 public 타입의 패키지들을 지정합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628349382892&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;exports packagename;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;exports-to 키워드는 정확히 어떤 모듈이 패키지에 접근할 수 있는지 명시할 때 사용합니다. 이것을 qualified export라고 합니다. 접근할 수 있는 모듈들은 콤마로 구분된 리스트로 작성할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1628349455575&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;exports packagename to modulename;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1628349464959&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;exports packagename to
	modulename1,
	modulename2,
	modulename3;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. uses&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;uses 키워드는 이 모듈에서 사용하는 service를 지정합니다. service란 인터페이스를 구현한 클래스, 추상클래스를 확장한 클래스의 객체를 말합니다. uses 키워드는 이 모듈을 service의 consumer로 만드는 것이기도 합니다. uses 키워드로 선언하는 인터페이스나 추상 클래스들은 이 모듈 안에 존재합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628349574079&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;uses classpath.interfacename;

uses classpath.abstractclassname;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. provides-with&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;provides-with 키워드는 이 모듈이 제공하는 service의 구현체를 지정할 때 사용합니다. 이 모듈을 service의 provider로 만드는 것이기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;provides 부분에는 인터페이스나 추상클래스를 선언하고, with 부분에는 이 인터페이스를 구현하는 클래스나 추상클래스를 확장하는 클래스를 선언합니다. provides-with로 선언하는 인터페이스나 추상클래스들은 다른 모듈에 존재합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628349647442&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;provides classpath.interfacename with implementation;

provides classpath.abstractclassname with extendedclassname;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. open, opens, opens-to&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 9 이전에는 reflection을 사용하여 패키지의 모든 클래스들과 그 멤버에 대해 알 수 있었습니다. 따라서 제대로 캡슐화되지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 시스템의 핵심 동기는 강력한 캡슐화입니다. 디폴트로 모듈 안의 클래스들은 다른 모듈에서 접근할 수 없습니다. public이고 이 패키지를 명시적으로 exports해야만 접근할 수 있습니다. open, opens, opens-to 키워드로 원하는 패키지만 공개할 수 있습니다. Java 9에서부터는 reflection에도 이 사항이 적용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 런타임 시에만 접근할 수 있는 패키지를 지정합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628349773659&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;opens packagename&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 런타임 시에만 접근할 수 있는 패키지를 특정 모듈에서만 접근할 수 있도록 명시합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628349782540&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;opens packagename to comma-separated-list-of-modules&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 런타임 시에만 모듈의 모든 패키지들을 접근할 수 있도록 지정합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628349790259&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;open module modulename {
   // module directives
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;* 아래의 링크를 참고하여 작성되었습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.oracle.com/kr/corporate/features/understanding-java-9-modules.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.oracle.com/kr/corporate/features/understanding-java-9-modules.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item tenping&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;SMALL&lt;/div&gt;
    &lt;tenping class=&quot;adsbytenping&quot; style=&quot;width: 100%; max-width: 768px; margin: 0 auto; display: block;&quot; mediaid=&quot;3914974&quot; tenping-ad-display-type=&quot;UD8Mia8gyIoT5Z2MT6VB3Q%3d%3d&quot;&gt;&lt;/tenping&gt;
    &lt;script src=&quot;//tads.tenping.kr/scripts/adsbytenping.min.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>Java</category>
      <category>JPMS</category>
      <category>Module</category>
      <category>자바 모듈</category>
      <author>림 림</author>
      <guid isPermaLink="true">https://limdevbasic.tistory.com/21</guid>
      <comments>https://limdevbasic.tistory.com/21#entry21comment</comments>
      <pubDate>Sun, 8 Aug 2021 00:25:22 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Security] 스프링 시큐리티 인증 아키텍처 컴포넌트</title>
      <link>https://limdevbasic.tistory.com/20</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;스프링 시큐리티에서 제공하는 기능 ⭐️⭐️⭐️&lt;/h2&gt;
&lt;p&gt;스프링 시큐리티는 사용자를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인증&lt;/b&gt;하고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;권한&lt;/b&gt;을 부여하는 기능을 제공합니다. 또, 여러 공격에 대해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;보호&lt;/b&gt;하는 기능을 제공합니다.&lt;/p&gt;
&lt;p&gt;그 중에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #cff2b6;&quot;&gt;인증과 권한&lt;/span&gt;은 스프링 시큐리티에서 가장 중요한 보안 개념입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인증(Authentication)&lt;/h3&gt;
&lt;p&gt;인증은 '&lt;b&gt;누구&lt;/b&gt;'인지를 검증하는 과정입니다.&amp;nbsp;&lt;br /&gt;사용자가 특정 자원에 접근하기 위해서는 그럴 권한이 있는 사용자라는 것을 증명해야합니다.&lt;br /&gt;따라서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용자는 사용자를 증명하기 위한 정보(credentials)를 제공하고, 인증은 바로 그 정보를 검증하는 것&lt;/b&gt;을 말합니다.&lt;/p&gt;
&lt;p&gt;사용자를 인증하는 흔한 방법 중에 하나는 사용자에게 이름(username)과 비밀번호(password)를 입력받는 것입니다.&lt;br /&gt;인증이 완료되면 스프링 시큐리티는 사용자가 '누구'인지 확인할 수 있게되고, 그 사용자의 권한에 따라 자원을 제공하고 보호하는 기능을 제공합니다.&lt;/p&gt;
&lt;p&gt;스프링 시큐리티는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;아키텍처 컴포넌트&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인증 매커니즘&lt;/b&gt;을 통해 인증 기능을 제공합니다.&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;아키텍처 컴포넌트&lt;/b&gt;에는 다음과 같은 것들이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SecurityContextHolder&lt;/b&gt;: 인증된 사용자에 대한 상세 정보를 저장하는 공간.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SecurityContext&lt;/b&gt;: 현재 인증된 사용자에 대한 정보. SecuritycontextHolder에 저장되며 Authentication을 담고 있습니다.&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Authentication&lt;/b&gt;: 현재 인증된 사용자의 고유 아이덴티티(principal), 자격 증명 정보(credentials), 역할 정보(authorities).&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;GrantedAuthority&lt;/b&gt;: Authentication에 포함되는 사용자의 역할 정보.&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;AuthenticationManager&lt;/b&gt;:&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;스프링 시큐리티의 필터들이 인증을 수행하기 위해 이용하는 API. 시큐리티 필터로부터 Authentication을 입력받음.&lt;/span&gt;&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ProviderManager&lt;/b&gt;: AuthenticationManager의 구현체. 여러 AuthenticationProvider의 그룹.&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;AuthenticationProvider&lt;/b&gt;: 각각 하나의 타입의 인증을 맡아서 인증을 수행.&lt;br /&gt;- Request Credentials with&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;AuthenticationEntryPoint&lt;/b&gt;: 사용자에게 자격 증명 정보를 요청.&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;AbstractAuthenticationProcessingFilter&lt;/b&gt;: 사용자로부터 받은 자격 증명 정보를 인증하는 기본 필터.&lt;/p&gt;
&lt;p&gt;각각의 아키텍처 컴포넌트에 대해 살펴보겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[SecurityContextHolder]&lt;/h4&gt;
&lt;p&gt;SecurityContextHolder는 스프링 시큐리티가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인증된 사용자에 대한 상세 정보를 저장하는 공간&lt;/b&gt;입니다.&lt;br /&gt;즉, 현재 SecurityContextHolder가 어떤 값을 포함하고 있다면 두 가지를 의미한다고 볼 수 있습니다.&lt;br /&gt;바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;현재 인증된 사용자가 있다는 것&lt;/b&gt;과 SecurityContextHolder가 포함하고 있는 값이 그&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용자에 대한 정보&lt;/b&gt;라는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;securitycontextholder.png&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;179&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLruJu/btqRx08ZqXO/f5Ch33DbKc6nceKgRzCxn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLruJu/btqRx08ZqXO/f5Ch33DbKc6nceKgRzCxn0/img.png&quot; data-alt=&quot;SecurityContextHolder 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLruJu/btqRx08ZqXO/f5Ch33DbKc6nceKgRzCxn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLruJu%2FbtqRx08ZqXO%2Ff5Ch33DbKc6nceKgRzCxn0%2Fimg.png&quot; data-filename=&quot;securitycontextholder.png&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;179&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SecurityContextHolder 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;SecurityContextHolder의 구조는 위의 사진과 같습니다.&lt;br /&gt;SecurityContextHolder는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SecurityContext&lt;/b&gt;를 담고 있고, SecurityContext는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Authentication&lt;/b&gt;을 담고 있습니다.&lt;br /&gt;그리고 Authentication은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Principal&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Credentials&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Authorities&lt;/b&gt;를 담고 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609046627973&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SecurityContext context = SecurityContextHolder.createEmptyContext(); 
Authentication authentication =
    new TestingAuthenticationToken(&quot;username&quot;, &quot;password&quot;, &quot;ROLE_USER&quot;); 
context.setAuthentication(authentication);

SecurityContextHolder.setContext(context); &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;코드를 보면 SecurityContextHolder의 createEmptyContext()를 통해 SecurityContext 객체를 초기화할 수 있습니다.&lt;br /&gt;그리고 SecurityContext의 setAuthentication()를 통해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Principal, Credentials, Authorities 값을 넣은&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;Authentication 객체를 초기화할 수 있습니다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;그리고 나서 SecurityContextHolder의 setContext()를 통해 SecurityContext를 SecurityContextHolder에 저장함으로써 현재 인증된 사용자에 대한 정보를 저장할 수 있습니다.&lt;br /&gt;현재 인증된 사용자에 대한 정보를 얻으려면 SecurityContextHolder의 getContext()를 이용하면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[SecurityContext]&lt;/h4&gt;
&lt;p&gt;SecurityContext는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;현재 인증된 사용자에 대한 정보&lt;/b&gt;입니다.&lt;br /&gt;SecurityContextHolder를 통해 얻을 수 있고, Authentication을 담는 객체입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[Authentication]&lt;/h4&gt;
&lt;p&gt;Authentication은 스프링 시큐리티의 두 가지 목적으로 사용됩니다.&lt;/p&gt;
&lt;p&gt;1)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인증을 위해 사용자의 정보를 제공&lt;/b&gt;하기 위해 사용됩니다. 인증을 수행하기 위한 API인 AuthenticationManager의 입력으로 전달됩니다.&lt;br /&gt;2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;현재 인증된 사용자&lt;/b&gt;를 나타내는 데에 사용됩니다. SecurityContextHolder로부터 SecurityContext를 얻고, SecurityContext로부터 Authentication을 얻어 현재 인증된 사용자를 나타낼 수 있습니다.&lt;/p&gt;
&lt;p&gt;Authentication은 세 가지를 포함하고 있습니다.&lt;/p&gt;
&lt;p&gt;1)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;principal&lt;/b&gt;: 고유의 사용자를 나타냅니다. username/password로 인증을 할 경우, principal은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UserDetails&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;객체가 됩니다.&lt;br /&gt;2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;credentials&lt;/b&gt;: 자격 증명을 나타냅니다. 예를 들면 password가 될 수 있습니다.&lt;br /&gt;3)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;authorities&lt;/b&gt;: 역할이나 접근 범위를 나타내는 GrantAuthority 객체입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[GrantedAuthority]&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;역할(role)이나 범위(scopes)를 나타내는 객체&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;GrantedAuthority는 Authentication 객체에 포함된 authorities입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;Authentication.getAuthorities()를 통해 얻을 수 있는데, 이 메소드는 GrantedAuthority의 컬렉션을 반환합니다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;고수준의 의미상으로 생각하면 권한이라고 생각할 수도 있지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;GrantedAuthority는 사용자(principal)에게 허가된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;권한이 아니라&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;ROLE_ADMIN, ROLE_HR_SUPERVISER과 같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;역할 정보&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[AuthenticationManager]&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;스프링 시큐리티의 필터들이 인증을 수행하기 위해 이용하는 API&lt;/b&gt;입니다.&lt;br /&gt;AuthenticaionManager의 주 구현체는 ProviderManager입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[ProviderManager &amp;amp; AuthenticationProvider]&lt;/h4&gt;
&lt;p&gt;ProviderManager는 가장 자주 쓰이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;AuthenticationManager의 구현체&lt;/b&gt;입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;ProviderManager는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;여러 개의&amp;nbsp;AuthenticationProvider들을 포함&lt;/b&gt;합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;각각의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;AuthenticationProvider는 하나의 타입의 인증을 맡아서 수행&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;예를 들어, DaoAuthenticationProviders는 username/password 기반의 인증을 수행하고, JwtAuthenticationProvider는 JWT토큰을 인증합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;AuthenticationProvider는 인증의 성공/실패의 결과를 제공&lt;/b&gt;합니다. 만약 성공/실패의 결정을 내릴 수 없다면, 결정을 내릴 수 없음을 나타내고 다른 AuthenticationProvider에게 결정을 위임합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;475&quot; height=&quot;NaN&quot; data-filename=&quot;providermanager.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;354&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UoxFc/btqRAjHoN34/NPB6rlLKakkPsziyJ85NxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UoxFc/btqRAjHoN34/NPB6rlLKakkPsziyJ85NxK/img.png&quot; data-alt=&quot;ProviderManager&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UoxFc/btqRAjHoN34/NPB6rlLKakkPsziyJ85NxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUoxFc%2FbtqRAjHoN34%2FNPB6rlLKakkPsziyJ85NxK%2Fimg.png&quot; width=&quot;475&quot; height=&quot;NaN&quot; data-filename=&quot;providermanager.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;354&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ProviderManager&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;만약 마지막 AuthenticationProvider까지 내려갔는데 인증을 할 수 없으면, ProviderNotFoundException 예외가 발생하고 인증에 실패하게 됩니다.&lt;/p&gt;
&lt;p&gt;ProviderManager는 선택적으로 참조할 수 있는 상위 AuthenticationManager를 구성할 수 있습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;만약 모든 AuthenticationProvider들이 인증을 수행할 수 없으면, 상위의 AuthenticationManager를 참조하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;267&quot; height=&quot;NaN&quot; data-filename=&quot;providermanager-parent.png&quot; data-origin-width=&quot;301&quot; data-origin-height=&quot;267&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I6viH/btqRxZh66tx/PmqcKUM7cHMN2F0GWA6X7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I6viH/btqRxZh66tx/PmqcKUM7cHMN2F0GWA6X7K/img.png&quot; data-alt=&quot;ProviderManager-parent&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I6viH/btqRxZh66tx/PmqcKUM7cHMN2F0GWA6X7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI6viH%2FbtqRxZh66tx%2FPmqcKUM7cHMN2F0GWA6X7K%2Fimg.png&quot; width=&quot;267&quot; height=&quot;NaN&quot; data-filename=&quot;providermanager-parent.png&quot; data-origin-width=&quot;301&quot; data-origin-height=&quot;267&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ProviderManager-parent&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여러 ProvideeManager가 하나의 AuthenticationManager를 공유하도록 구성함으로써&amp;nbsp;&lt;/span&gt;여러 개의 인증 매커니즘을 여러 ProviderManager를 통해 수행하고, 공통적으로 수행하는 인증은 AuthenticationManager에서 수행하게 할 수도 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;547&quot; height=&quot;NaN&quot; data-filename=&quot;providermanagers-parent.png&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;305&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SG4jn/btqRGpUBxjK/kGNrZdt4CHkl4k1gTVM0Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SG4jn/btqRGpUBxjK/kGNrZdt4CHkl4k1gTVM0Kk/img.png&quot; data-alt=&quot;ProviderManagers-parent&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SG4jn/btqRGpUBxjK/kGNrZdt4CHkl4k1gTVM0Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSG4jn%2FbtqRGpUBxjK%2FkGNrZdt4CHkl4k1gTVM0Kk%2Fimg.png&quot; width=&quot;547&quot; height=&quot;NaN&quot; data-filename=&quot;providermanagers-parent.png&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;305&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ProviderManagers-parent&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[Request Credentials with AuthenticationEntryPoint]&lt;/h4&gt;
&lt;p&gt;AuthenticationEntryPoint는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;클라이언트에게 자격 증명 정보(credentials)를 요청하는 HTTP 응답을 보내는&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데에 사용됩니다.&lt;/p&gt;
&lt;p&gt;사용자가 미리 로그인을 하는 경우에는 스프링 시큐리티가 사용자에게 자격 증명 정보를 요청하는 HTTP 응답을 보낼 필요가 없습니다.&lt;br /&gt;그런데 만약, 인증되지 않은 사용자가 어떤 자원에 대해 요청을 보내면, AuthenticationEntryPoint의 구현체를 통해 클라이언트에게 자격 증명 정보를 요청합니다.&lt;/p&gt;
&lt;p&gt;AuthenticationEntryPoint는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;로그인 페이지로 리다이렉트&lt;/b&gt;하거나,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;클라이언트에게 401 응답 코드와 함께 WWW-Authenticate 헤더&lt;/b&gt;를 보내는 작업을 수행합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[AbstractAuthenticationProcessingFilter]&lt;/h4&gt;
&lt;p&gt;AbstractAuthenticationProcessingFilter는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용자의 자격 증명 정보를 인증하는 기본 필터&lt;/b&gt;로 사용됩니다.&lt;/p&gt;
&lt;p&gt;스프링 시큐리티가 AuthenticationEntryPoint로 자격 증명 정보를 요청하고 나면, AbstractAuthenticationProcessingFilter가 인증 요청을 수행합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;520&quot; height=&quot;NaN&quot; data-filename=&quot;abstractauthenticationprocessingfilter.png&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;714&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK908n/btqRGpG5kkE/v6KmxC6vSVf6pf4Eb3oiY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK908n/btqRGpG5kkE/v6KmxC6vSVf6pf4Eb3oiY0/img.png&quot; data-alt=&quot;AbstractAuthenticationProcessingFilter&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK908n/btqRGpG5kkE/v6KmxC6vSVf6pf4Eb3oiY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK908n%2FbtqRGpG5kkE%2Fv6KmxC6vSVf6pf4Eb3oiY0%2Fimg.png&quot; width=&quot;520&quot; height=&quot;NaN&quot; data-filename=&quot;abstractauthenticationprocessingfilter.png&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;714&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AbstractAuthenticationProcessingFilter&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;1) 사용자가 자격 증명 정보를 제출하면, AbstractAuthenticationProcessingFilter가 Authentication객체를 생성합니다.&lt;br /&gt;Authentication객체는 AbstractAuthenticationProcessingFilter의 서브클래스에 의해 생성되고, 그 타입이 결정됩니다.&lt;br /&gt;예를 들어, UsernamePasswordAuthenticationFilter는 사용자로부터 받은 username과 password로부터 UsernamePasswordAuthenticationToken을 생성합니다.&lt;/p&gt;
&lt;p&gt;2) Authentication객체가 AuthenticationManager에게 전달됩니다.&lt;/p&gt;
&lt;p&gt;3) 만약 인증에 실패하면, SecurityContextHolder의 값이 지워지고, RememberMeService.joginFail()이 실행됩니다.&lt;br /&gt;그리고 AuthenticationFailureHandler가 실행됩니다.&lt;/p&gt;
&lt;p&gt;4) 만약 인증에 성공하면, SessionAuthenticationStrategy가 새로운 로그인이 되었음을 알리고, Authentication이 SecurityContextHolder에 저장됩니다. 이후에 SecurityContextPersistenceFIlterrk SecurityContext를 HttpSession에 저장하면서 로그인 세션 정보가 저장됩니다.&lt;br /&gt;그리고 RememberMeServices.loginSucess()가 실행됩니다. 또, ApplicationEventPublisher가 InteractiveAuthenticationSuccessEvent를 발생시키고 AuthenticationSuccessHandler가 실행됩니다.&lt;/p&gt;</description>
      <category>Spring</category>
      <category>Spring Security</category>
      <category>스프링 시큐리티</category>
      <category>인증</category>
      <category>인증 아키텍처</category>
      <author>림 림</author>
      <guid isPermaLink="true">https://limdevbasic.tistory.com/20</guid>
      <comments>https://limdevbasic.tistory.com/20#entry20comment</comments>
      <pubDate>Sun, 27 Dec 2020 14:25:35 +0900</pubDate>
    </item>
  </channel>
</rss>