반응형

 

HTTP는 다양한 메서드를 제공하여 클라이언트가 서버에 요청을 보내고, 서버는 해당 요청에 대한 응답을 반환합니다. 가장 널리 사용되는 HTTP 메서드는 다음과 같습니다

💡 요구사항 - 회원 정보 관리 API를 만들어라

API URI 설계 (URI : Uniform Resource Identifier)

회원 목록 조회 /read-member-list
회원 조회 /read-member-by-id
회원 등록 /create-member
회원 수정 /update-member
회원 삭제 /delete-member

ㅡㅡㅡㅡ 위의 리소스가 좋은 URI 설계일까?ㅡㅡㅡㅡ 가장 중요한 건 리소스 식별입니다.

 

리소스란 ❓

리소스(Resource)는 웹 애플리케이션에서 클라이언트가 요청하고 서버가 제공하는 데이터나 서비스를 의미합니다. 일반적으로 웹 애플리케이션에서 리소스는 웹 페이지, 이미지, 문서, 데이터베이스 레코드 등과 같은 것들을 포함합니다. 리소스는 고유한 식별자(예: URL)를 가지며, 클라이언트는 해당 식별자를 사용하여 리소스에 접근하고 요청할 수 있습니다.

리소스는 웹 애플리케이션의 중요한 구성 요소로, 클라이언트는 HTTP 메서드(GET, POST, PUT, DELETE 등)를 사용하여 리소스에 대한 요청을 보냅니다. 서버는 이러한 요청을 처리하고, 적절한 응답을 반환하여 클라이언트에게 전달합니다. 이를 통해 클라이언트는 웹 애플리케이션에서 필요한 데이터를 조회, 생성, 업데이트, 삭제할 수 있습니다.

리소스는 일반적으로 웹 애플리케이션의 상태를 나타내는 정보를 포함하고, 클라이언트는 이러한 리소스를 조작하여 웹 애플리케이션의 동작을 제어하거나 데이터를 처리합니다. RESTful 웹 서비스의 경우 리소스는 RESTful API의 핵심 개념이며, 클라이언트는 URI(Uniform Resource Identifier)를 사용하여 리소스를 식별하고 조작합니다.

 

URI(Uniform Resource Identifier) 계층 구조리소스를 계층적으로 구성하여 효율적이고 일관성 있게 관리할 수 있는 방법을 제공합니다. URI 계층 구조는 다음과 같은 방식으로 활용될 수 있습니다:

  1. 경로 구분: URI의 경로(Path)를 사용하여 리소스를 계층적으로 구분할 수 있습니다. 경로는 슬래시("/")로 구분되며, 각 경로 요소는 리소스의 상위 레벨을 의미합니다. 예를 들어, /users/john 경로는 "users"라는 상위 리소스 아래의 "john" 리소스를 식별합니다. 이러한 계층 구조를 활용하여 리소스를 조직화하고 접근할 수 있습니다.

  2. 부모-자식 관계: URI의 계층 구조를 활용하여 부모-자식 관계를 표현할 수 있습니다. 예를 들어, /categories/books와 /categories/electronics와 같은 URI는 "categories"라는 부모 리소스 아래에 "books"와 "electronics"라는 자식 리소스를 가지고 있음을 나타냅니다. 이러한 관계를 활용하여 리소스 간의 상호작용을 나타내거나 필요한 데이터를 추출할 수 있습니다.

  3. 컬렉션과 멤버: URI 계층 구조를 활용하여 컬렉션(Collection)과 멤버(Member)를 표현할 수 있습니다. 컬렉션은 여러 개의 리소스를 포함하는 상위 개념이고, 멤버는 개별 리소스를 나타냅니다. 예를 들어, /users는 사용자 컬렉션을, /users/{id}는 특정 사용자를 나타냅니다. 이러한 구조를 활용하여 컬렉션과 멤버 간의 관계를 표현하고 조작할 수 있습니다.

  4. 상태 전이(State Transition): URI 계층 구조는 상태 전이(State Transition)를 표현하는 데에도 활용될 수 있습니다. RESTful API에서는 리소스 간의 상태 전이를 URI와 HTTP 메서드를 조합하여 표현합니다. 예를 들어, /orders/{id}/cancel은 특정 주문의 상태를 취소로 변경하는 상태 전이를 의미합니다. 이러한 URI 계층 구조를 통해 리소스의 상태 전이를 명확하게 표현하고 제어할 수 있습니다.

URI 계층 구조를 활용하여 리소스를 적절하게 조직하고 식별하는 것은 RESTful 아키텍처에서 중요한 개념입니다. 계층 구조를 일관성 있게 설계하고 사용하여 클라이언트가 리소스를 쉽게 찾고 조작할 수 있도록 지원할 수 있습니다.

 

URI(Uniform Resource Identifier) 설계 시 리소스 식별은 URI를 통해 고유한 리소스를 식별하는 것을 의미합니다. URI는 웹에서 리소스에 접근할 수 있는 주소로, 리소스를 고유하게 식별하기 위해 사용됩니다.

리소스 식별은 다음과 같은 원칙을 따라야 합니다:

  1. 유일성: 각 리소스는 고유한 식별자를 가져야 합니다. 다른 리소스와 중복되지 않는 유니크한 식별자를 할당해야 합니다. 이를 통해 각각의 리소스가 독립적으로 식별되고 접근될 수 있습니다.
  2. 명확성: 리소스 식별자는 클라이언트가 어떤 리소스에 접근하고 있는지 명확하게 알 수 있어야 합니다. 의미를 파악하기 쉬운 명시적인 식별자를 사용하는 것이 좋습니다.

  3. 지속성: 리소스 식별자는 변하지 않는 것이 좋습니다. 리소스의 위치나 이름이 변경되지 않는 한, 동일한 식별자로 접근할 수 있어야 합니다. 이는 클라이언트가 항상 유효한 식별자를 사용하여 리소스에 접근할 수 있도록 보장합니다.

리소스 식별은 RESTful 아키텍처의 핵심 원칙 중 하나이며, 웹 애플리케이션에서 리소스를 효과적으로 관리하고 조작하기 위해 중요합니다. 클라이언트는 URI를 사용하여 원하는 리소스에 접근하고 RESTful API를 통해 해당 리소스를 조작할 수 있습니다. 따라서 URI 설계 시 리소스 식별은 명확하고 일관성 있게 이루어져야 합니다.

📕 HTTP 메서드

가장 널리 사용되는 HTTP 메서드는 다음과 같습니다:

  1. GET : 서버로부터 리소스(데이터)를 가져오기 위해 사용되는 메서드입니다. 주로 데이터 조회나 검색에 사용됩니다. GET 요청은 주소 표시줄에 쿼리 매개변수로 데이터를 전달할 수 있습니다.
  2. POST : 서버에 새로운 데이터를 전송하기 위해 사용되는 메서드입니다. 주로 데이터 생성이나 업데이트에 사용됩니다. POST 요청은 요청 본문에 데이터를 담아 서버로 전송합니다. 데이터를 담아서 클라이언트가 서버에 보내야 합니다.
  3. PUT : 서버에 새로운 데이터를 전송하거나 기존 데이터를 업데이트하기 위해 사용되는 메서드입니다. PUT 요청은 요청 본문에 데이터를 담아 지정된 리소스를 대체합니다. 파일을 폴더에 넣는 것과 비슷합니다. 없으면 생성, 있으면 덮어씌어집니다.
  4. DELETE : 서버에서 데이터를 삭제하기 위해 사용되는 메서드입니다. DELETE 요청은 지정된 리소스를 삭제합니다.
  5. PATCH : 서버에 새로운 데이터를 부분적으로 업데이트하기 위해 사용되는 메서드입니다. PATCH 요청은 요청 본문에 업데이트할 데이터만 포함하며, 해당 리소스의 일부만 수정합니다.
  6. HEAD : GET 요청과 유사하지만, 실제 데이터를 가져오지 않고 응답 헤더만 가져옵니다. 주로 리소스의 메타데이터를 확인할 때 사용됩니다.
  7. OPTIONS : 서버가 지원하는 HTTP 메서드 목록을 요청합니다. 주로 CORS (Cross-Origin Resource Sharing) 정책을 확인하기 위해 사용됩니다.

 

✅ GET, POST

👉 GET 메서드 👈

HTTP 메서드 중 GET은 서버로부터 리소스를 요청하기 위해 사용되는 메서드입니다. GET 요청은 서버로부터 데이터를 가져오는 역할을 합니다. 일반적으로 GET 메서드는 조회에서만 사용하며 , 요청한 리소스를 가져와서 응답으로 반환하며, 서버의 상태나 데이터를 변경하지 않습니다.

GET 메서드는 주로 브라우저에서 웹 페이지나 이미지, 동영상 등을 요청할 때 사용됩니다. GET 요청은 URL에 데이터를 포함하여 전송할 수 있으며, 이러한 데이터는 쿼리 파라미터(Query Parameter)의 형태로 전달됩니다. 예를 들어, https://example.com/products?id=123와 같은 URL에서 id=123은 GET 요청에 대한 쿼리 파라미터입니다.

GET 메서드의 주요 특징은 다음과 같습니다:

  • 요청한 리소스를 가져오기 위해 사용됨
  • 데이터를 URL에 쿼리 파라미터로 전달
  • 캐싱이 가능하므로 동일한 요청에 대한 반복적인 요청 시 서버 부하를 줄일 수 있음
  • 요청에 대한 응답으로 데이터를 반환 (HTML, JSON, XML 등)

GET 메서드는 보안이나 데이터 변경과 관련된 작업에는 적합하지 않습니다. 데이터의 생성, 수정, 삭제 등을 요청하기 위해서는 다른 HTTP 메서드 (POST, PUT, DELETE 등)를 사용해야 합니다.

GET 메서드는 브라우저에서 주로 사용되지만, HTTP 클라이언트 라이브러리나 API 호출에서도 GET 메서드를 사용하여 서버로부터 데이터를 요청할 수 있습니다.

👉 POST메서드 👈

HTTP 메서드 중 POST는 클라이언트에서 서버로 데이터를 전송하기 위해 사용되는 메서드입니다. POST 요청은 서버에 새로운 리소스를 생성하거나 기존 리소스를 수정하기 위해 데이터를 전달합니다.

POST 메서드는 일반적으로 HTML 폼(form)을 통해 사용자로부터 입력 받은 데이터를 서버로 전송할 때 사용됩니다. 예를 들어, 회원 가입 폼이나 댓글 작성 폼에서 사용자가 입력한 데이터를 서버로 전송할 때 POST 요청을 사용합니다. POST 요청은 요청 본문(Request Body)에 데이터를 담아 전송하며, URL에는 데이터가 노출되지 않습니다.

POST 메서드의 주요 특징은 다음과 같습니다:

  • 서버에 새로운 리소스를 생성하거나 기존 리소스를 수정하기 위해 사용 - 서버가 아직 식별하지 않은 새 리소스를 생성
  • 요청에 대한 응답으로 생성된 리소스의 정보나 상태를 반환 - 단순히 데이터를 생성하거나, 변경하는 것을 넘어서 프로세스를 처리해야 하는 경우 (ex) 상품 주문에서 → 결제 완료 → 배달 시작(배달시작 버튼을 누르는 것도 POST를 사용) → 배달완료 처럼 단순히 값 변경을 넘어 프로세스의 상태가 변경되는 경우 POST의 결과로 새로운 리소스가 생성되지 않을 수도 있습니다.
  • 다른 메서드로 처리하기 어려운 경우 (ex) JSON으로 조회 데이터를 넘겨야 하는데, GET 메서드를 사용하기 어려운 경우, 애매하면 POST를 사용

POST 메서드는 클라이언트가 서버에게 데이터를 전송하고, 서버는 해당 데이터를 처리하여 새로운 리소스를 생성하거나 기존 리소스를 변경하는 데 사용됩니다.
중요한 점은 POST 요청은 서버의 상태를 변경시키는 작업에 사용되므로, 이러한 작업을 수행할 때에는 적절한 권한과 보안 메커니즘이 필요합니다.

 

✅ PUT, PATCH, DELETE

👉 PUT 메서드 👈

PUT 메서드는 웹 서버에 새로운 리소스를 생성하거나 기존 리소스를 업데이트하는 데 사용됩니다. 클라이언트는 PUT 요청을 통해 서버에 데이터를 전송하고, 해당 데이터를 서버에 저장하거나 갱신할 수 있습니다. 쉽게 이야기하면 리소스를 대체하여 덮어씌워 버립니다.

PUT 요청은 일반적으로 RESTful API에서 자원을 생성하거나 업데이트하는 데 사용됩니다. 클라이언트는 PUT 요청을 보내면 원하는 자원의 위치(URI)와 업데이트할 데이터를 함께 전송합니다. 서버는 해당 위치에 자원을 생성하거나 업데이트하고, 작업 결과를 클라이언트에 응답합니다.

PUT 요청은 클라이언트가 전체 엔티티(리소스를 지정/식별)를 서버에 제공하는 것을 의미합니다. 따라서 클라이언트가 전체 리소스의 위치를 알고 URI를 지정하는 점이 POST와의 큰 차이점입니다. 전체 리소스의 내용을 PUT 요청 본문에 포함하여 서버에 전송해야 합니다. 이미 존재하는 리소스를 업데이트하는 경우에도 클라이언트는 전체 리소스를 제공해야 합니다. 그리고 요청한 리소스의 데이터로 기존 리소스들이 대체되어 데이터가 바뀌어버립니다.

PUT 메서드는 안전한 메서드로 간주되지 않습니다. 이는 서버의 상태나 데이터를 변경할 수 있기 때문입니다. 따라서 PUT 요청은 서버에 영향을 줄 수 있는 작업을 수행하기 때문에 주의해서 사용해야 합니다.

👉 PATCH 메서드 👈

리소스의 업데이트를 가능하게 해주는 메서드 입니다. PATCH 메서드는 서버에게 리소스의 부분적인 변경을 요청하는 데 사용됩니다. PUT 메서드를 사용하게되면 기존에 남아있던 리소스의 일부 변경이 아닌 전체가 대체되는데 이와 달리 PATCH메서드를 사용하게 되면 클라이언트는 전체 리소스를 보내지 않고도 리소스의 일부를 수정할 수 있습니다. 클라이언트는 PATCH 요청을 통해 변경하고자 하는 리소스의 일부를 지정하고, 서버는 해당 부분만 수정합니다. 이는 리소스의 일부를 효율적으로 업데이트할 수 있는 장점을 가지고 있습니다.

👉 DELETE 메서드 👈

DELETE 메서드는 서버에게 리소스의 삭제를 요청하는 데 사용됩니다. 클라이언트가 DELETE 요청을 보내면 서버는 해당 리소스를 삭제하고, 삭제 작업의 결과를 클라이언트에게 응답합니다. DELETE 요청을 통해 리소스를 삭제하면 해당 리소스에 대한 접근이 불가능해지며, 서버에서 완전히 제거됩니다.

728x90

'[HTTP]' 카테고리의 다른 글

[HTTP] HTTP 헤더  (0) 2023.07.27
[HTTP] HTTP 상태 코드  (0) 2023.07.26
[HTTP] HTTP 메서드의 속성  (0) 2023.07.15
[HTTP] URI와 웹 브라우저 요청 흐름 (URL, HTTP)  (0) 2023.06.28
[HTTP] 인터넷 통신  (0) 2023.06.25
반응형

컬렉션이란 배열처럼 동일한 타입을 묶어서 관리하는 자료구조입니다. 저장 공간의 크기 (capacity)를 동적으로 관리합니다.

프레임워크란 클래스를 정의하거나 설계할 때 어떤 원칙이나 구조를 가지고 클래스와 인터페이스를 설계한 것을 프레임워크라고합니다. ( 클래스와 인터페이스의 모임)

컬렉션 프레임워크란❓

컬렉션 프레임워크(Collection Framework)리스트, 스택, 큐, 트리 등의 자료구조에 정렬 , 탐색 등의 알고리즘을 구조화 해놓은 프레임워크이자 java에서 데이터 그룹을 다루기 위한 클래스들의 집합입니다.

프레임워크는 데이터 그룹을 저장하고 조작하기 위한 표준화된 방법을 제공하여 개발자들이 데이터 구조를 효율적으로 관리할 수 있도록 돕습니다. 이러한 컬렉션 프레임워크는 자바의 인터페이스(interface)를 사용하여 구현됩니다.

컬렉션 프레임워크는 다양한 인터페이스와 클래스로 구성되어 있으며, 각각의 클래스는 특정한 데이터 구조와 동작 방식을 가지고 있습니다. 주요한 인터페이스와 클래스로는 다음과 같은 것들이 있습니다

컬렉션 프레임워크는 데이터 그룹을 다루기 위한 다양한 기능들을 제공합니다. 데이터의 추가, 삭제, 검색, 정렬 등을 쉽게 처리할 수 있으며, 각각의 클래스는 내부적으로 데이터 구조를 효율적으로 관리하도록 구현되어 있습니다. 이를 통해 개발자는 데이터 구조에 대한 세부적인 관리 없이 간편하게 데이터를 다룰 수 있습니다.

1. List<E>

순서가 있는 데이터 그룹을 저장하는 인터페이스입니다. 컬렉션은 제네릭타입으로 선언되고 동일한 타입을 저장할 때, 제네릭 타입으로 선언된 데이터들만 초기화가 가능합니다. 중복된 요소를 허용하며, 대표적인 클래스로는 ArrayList, LinkedList, Vector 등이 있습니다.

배열의 경우, 초기화되면 저장크기가 고정이 되어 이 후 각 인덱스에 저장된 값들을 제거하거나 추가하더라도 인덱스의 총 길이는 동적으로 바뀌지가 않습니다. LIST의 경우, 동적 컬렉션을 생성하여 데이터의 추가 삭제가 가능합니다. 그에 따른 저장공간의 길이도 자동으로 늘어나고 줄게 됩니다.

💡 List <E> 컬렉션의 객체 생성 방법

 

List <E> interface의 구현 클래스 생성자로 동적 컬렉션 생성 (데이터의 추가 삭제 가능)

  • 기본 생성자의 경우 원소 개를 저장할 수 있는 저장공간(capacity)를 확보합니다. 필요한 경우에 추가한다면 JVM이 동적으로 저장공간의 크기를 자동적으로 추가합니다. ex) List<Integer> aList1 = new ArrayList<Integer>(); → capacity(10)
  • 생성자 매개변수로 저장공간의 크기를 직접 넘겨줄 수 있습니다. (단, LinkedList<E>는 제외, capacity 지정 불가능) ex) List<Integer> aList2 = new ArrayList<Integer>(20) → capacity(20)

Arrays.asList( T(개수가 지정되지 않은 매개변수) ..) 메서드를 이용하여 정적 컬렉션 생성

  • 데이터의 추가(add) 삭제(remove) 불가능하며, 데이터의 변경(set)은 가능합니다. → 고정된 데이터를 저장하고 활용하고자 할 때 사용
    ex) List<제네릭타입지정> asList1 = Arrays.asList(제네릭타입데이터들);
    List<Integer> aList1 = Arrays.asList(1,2,3,4);
    내부적으로는 1,2,3,4가 담겨져 있는 Integer배열이 만들어졌고, 해당 배열을 List로 감싼 객체가 생성됩니다.
    여기서 내부적으로는 데이터가 고정적인 배열이 생성된 것이라 add() , remove()는 사용이 불가하고,
    데이터의 수는 변하지 않고 값만 변하게 하는 set() 메서드만 사용가능합니다.
    → 배열처럼 수집(collect)한 원소(Element)를 인덱스(index)로 관리 List<E>의 구현 클래스는 아래의 모든 메서드를 포함합니다.



https://velog.io/@mmy789/Java-컬렉션-프레임워크-1

 

  • toArray()메서드 : toArray() 메서드는 ArrayList의 요소들을 배열로 변환하는 메서드입니다. 이 메서드를 호출하면 ArrayList의 요소들이 배열로 복사되어 반환됩니다. toArray() 메서드에는 두 가지 형태가 있습니다
    1. 매개변수가 없는 toArray():
      • 이 형태의 toArray() 메서드는 Object 배열로 요소들을 복사하여 반환합니다.
      • 반환된 배열의 타입은 Object 배열이므로, 원하는 타입으로 형변환을 해주어야 합니다.
    2. 매개변수가 있는 toArray(T[] a):
      • 이 형태의 toArray() 메서드는 지정한 타입의 배열 **a**를 매개변수로 받아, 해당 배열로 요소들을 복사하여 반환합니다.
      • 만약 매개변수로 전달된 배열의 크기가 ArrayList의 크기보다 작을 경우, 새로운 배열이 생성되어 요소들이 복사됩니다.
      • 만약 매개변수로 전달된 배열의 크기가 ArrayList의 크기보다 크거나 같을 경우, ArrayList의 요소들이 매개변수로 전달된 배열에 복사되고, 남는 공간은 null로 채워집니다.
            Object[] object = aList3.toArray();
            System.out.println(Arrays.toString(object));
    
            Integer[] integer1 = aList3.toArray(new Integer[0]);
            System.out.println(Arrays.toString(integer1));  //출력 : [1,2,3]
            -> list인 aList3의 size()보다 작성된 선언공간이 크면 자동적으로 list의 size 크기를 가지는 배열이 생성
    
            Integer[] integer2 = aList3.toArray(new Integer[5]);
            System.out.println(Arrays.toString(integer2)); //출력 [1,2,3,null,null]
            -> list인 aList3의 size()가 작성된 선언공간 new Integer[5]보다 작은 경우 데이터가 채워진
               이 후의 공간에는 null값이 담기게 된다.


대표적인 List<E> 컬렉션의 클래스

  1. ArrayList<E> : ArrayList<E>는 제네릭을 사용하여 요소를 저장하는 동적 배열 클래스입니다. <E>는 제네릭 타입 매개변수로, ArrayList가 저장할 요소의 타입을 지정하는데 사용됩니다.
    ArrayList를 사용하려면 import java.util.ArrayList; 문을 통해 java.util 패키지에서 해당 클래스를 임포트한 후, 다음과 같이 ArrayList 객체를 생성하고 요소를 추가하고 접근할 수 있습니다

            import java.util.ArrayList;
    
            public class Main {
                public static void main(String[] args) {
                    ArrayList<String> list = new ArrayList<String>();
    
                    // 요소 추가
                    list.add("사과");
                    list.add("바나나");
                    list.add("딸기");
    
                    // 요소 접근
                    String fruit = list.get(1);
                    System.out.println(fruit); // 출력: 바나나
    
                    // 요소 삭제
                    list.remove(0);
                    System.out.println(list); // 출력: [바나나, 딸기]
                }
            }
    
            위의 예제에서 <String>은 ArrayList가 문자열 요소를 저장한다는 것을 명시하고 있습니다. 
            따라서 ArrayList에는 문자열만 저장할 수 있습니다. 만약 다른 타입의 요소를 저장하려면 
            <E> 자리에 해당 타입을 지정하면 됩니다.
  2. Vector<E> : Vector<E>는 Java의 컬렉션 프레임워크에서 제공하는 클래스로, 동적으로 크기가 조정되는 배열 형태의 자료구조입니다. ArrayList와 아주 유사하게 동일한 타입의 객체수집 (collection)` , 메모리의 동적할당, 데이터의 추가, 변경, 삭제 등의 메서드를 사용할 수 있는 공통적 기능을 제공하지만, 큰 차이점으론 Vector는 스레드 동기화(synchronized)가 되어 있어 멀티스레드 환경에서 안전하게 사용할 수 있습니다.

  3. LinkedList<E> : LinkedList<E>는 연결 리스트(linked list) 데이터 구조를 기반으로한 리스트(List) 구현체입니다. 앞뒤 요소(Element)로 정보의 데이터 위치를 관리합니다. LinkedList는 요소들을 연결한 노드(Node)로 구성되며, 각 노드는 데이터 요소와 다음 노드를 가리키는 참조(주소)로 이루어져 있습니다.

    각 데이터들의 왼쪽 오른쪽 데이터들의 위치를 알고 있습니다. 이러한 구조로 인해 요소들의 추가, 삭제, 삽입이 상대적으로 빠르게 이루어질 수 있지만, 검색(get)은 속도가 더 늦게 진행됩니다. (순서를 세어서 해당 토드를 찾아야 하기때문에)

  4. ArrayList<E>와 유사하지만 1) 디폴트 저장공간(10)만 사용하며 2) 생성자로 저장공간의 크기 지정이 불가한 점, 3) 데이터의 내부 저장방식이 index가 아닌 앞 뒤 객체의 위치정보를 저장한다는 차이점이 있습니다. 

        ArrayList<E>와 LinkedList<E> 가장 큰 차이점은 내부적인 데이터 구조입니다.

  1. 내부 데이터 구조:
    • ArrayList: 배열(Array)을 기반으로한 동적 배열 구조입니다. 요소들은 인덱스에 따라 순차적으로 저장됩니다. 인덱스로 직접적인 접근이 가능하며, 요소의 삽입과 삭제가 느리지만 요소의 조회가 빠릅니다.
    • LinkedList: 연결 리스트(Linked List)를 기반으로한 노드(Node)들이 연결된 구조입니다. 각 요소는 이전 노드와 다음 노드의 참조(주소)로 연결되어 있습니다. 요소의 삽입과 삭제가 빠르지만 인덱스로 직접적인 접근이 불가능하며, 요소의 조회가 느립니다.
  2. 데이터 접근 시간:
    • ArrayList: 인덱스로 요소에 직접 접근할 수 있으므로 요소의 조회가 빠릅니다. 삽입과 삭제가 배열의 크기 변동에 따라 발생하므로 비용이 크고, 요소를 중간에 삽입 또는 삭제하는 경우에는 뒤따라오는 요소들을 한 칸씩 이동해야 합니다.
    • LinkedList: 요소를 순차적으로 따라가야 하므로 인덱스로 직접 접근하는 것보다 접근 시간이 더 오래 걸립니다. 하지만 요소의 삽입과 삭제는 노드의 연결 관계만 변경하면 되므로 비교적 빠릅니다.
  3. 메모리 사용:
    • ArrayList: 내부적으로 배열을 사용하기 때문에 요소들을 연속적인 메모리 공간에 저장합니다. 따라서 공간 효율성이 높습니다.
    • LinkedList: 노드들이 연결되어 있기 때문에 각 요소마다 추가적인 노드 객체와 참조(주소)를 저장해야 하므로 메모리 사용량이 더 큽니다.

두 클래스는 사용 목적과 상황에 따라 선택되어야 합니다. ArrayList는 요소의 조회가 많고, 중간에 삽입/삭제가 적은 경우에 유리하며, LinkedList는 삽입/삭제가 빈번하고 순차적인 접근이 주로 발생하는 경우에 유리합니다.

 

 

728x90
반응형

 

✅ 제네릭 클래스 vs 제네릭 메서드의 차이점

  1. 범위: 제네릭 메서드는 특정 메서드 내에서만 제네릭 타입을 사용하고, 해당 메서드의 매개변수 타입이나 반환 타입을 제네릭으로 정의합니다. 반면에 제네릭 클래스는 클래스 전체에서 제네릭 타입을 사용하고, 클래스의 필드, 메서드, 생성자 등에서 제네릭 타입을 사용할 수 있습니다.

  2. 사용 방법: 제네릭 메서드는 메서드 선언 시에 타입 매개변수를 선언하고, 해당 메서드 내에서만 해당 타입을 사용합니다. 제네릭 클래스는 클래스 선언 시에 타입 매개변수를 선언하고, 클래스 전체에서 해당 타입을 사용할 수 있습니다.

  3. 타입 유연성: 제네릭 메서드는 각 메서드 호출 시에 사용하는 타입을 동적으로 지정할 수 있으므로, 호출할 때마다 다른 타입을 사용할 수 있습니다. 제네릭 클래스는 클래스 인스턴스를 생성할 때 타입을 지정하고, 해당 인스턴스의 타입은 고정됩니다.

  4. 코드 재사용성: 제네릭 메서드는 특정 메서드 내에서만 사용되므로 해당 메서드가 호출되는 범위 내에서만 재사용이 가능합니다. 제네릭 클래스는 여러 메서드에서 공통으로 사용되는 제네릭 타입을 정의하므로, 클래스 전체에서 재사용이 가능합니다.
    • 와일드 카드 : 불특정한 타입을 나타내는 데에 사용되며, 주로 제네릭 타입의 매개변수나 변수를 선언할 때 사용됩니다. 제네릭 클래스를 생성할 때, 참조변수에 지정된 제네릭 타입과 생성자에 지정돤 제네릭 타입은 일치해야 합니다. 만약 일치하지 않으면 컴파일 에러가 발생합니다.
      • 이때 제네릭 타입으로 ‘와일드 카드’를 사용하면 extends와 super로 상한과 하한을 제한할 수 있습니다.
      1. ? - 물음표 와일드카드(Unbounded Wildcard): 어떤 타입도 가능한 경우를 의미합니다. 예를 들어, **List<?>**는 어떤 종류의 요소든지 포함할 수 있는 리스트를 나타냅니다.
      2. ? extends 타입 - 상한 와일드카드(Upper Bounded Wildcard): 특정 타입 또는 그 타입을 상속받은 타입들만 가능한 경우를 의미합니다. . 예를 들어, List<? extends Number>는 Number 타입 또는 Number를 상속받은 타입들만인Integer, Double, Float 등을 받을 수 있는 리스트를 나타냅니다.
      3. ? super 타입 - 하한 와일드카드(Lower Bounded Wildcard) : 특정 타입의 상위 타입을 나타냅니다. 예를 들어, **List<? super Integer>**는 Integer 클래스와 그 상위 타입인 Number, Object 등을 받을 수 있는 리스트를 나타냅니다. 이렇게 사용되면 해당 타입과 그 상위 타입들에 대해서만 동작할 수 있습니다.

 

🎈 제네릭 타입 범위 제한

제네릭 타입 범위 제한(Generics Type Bounds)제네릭 클래스나 메서드에서 허용되는 타입의 범위를 제한하는 기능입니다. 이를 통해 제네릭 타입을 사용할 때 특정한 종류의 타입만을 허용하도록 제한할 수 있습니다. 이는 코드의 안정성과 타입 안정성을 높이는 데 도움이 됩니다.

  1. 타입 안정성 보장 : 특정한 종류의 타입만을 허용하므로, 잘못된 타입이 사용되는 것을 방지할 수 있습니다. 이로 인해 컴파일 시점에서 타입 체크를 수행하여 런타임 에러를 방지할 수 있습니다.

  2. 코드 재사용성 향상 : 특정한 종류의 타입으로 제한하면 해당 타입에 대한 특정한 동작 또는 기능을 구현할 수 있는 제네릭 클래스나 메서드를 작성할 수 있습니다. 이를 통해 코드의 재사용성과 유지보수성이 향상됩니다.

 

🎈 제네릭 타입 범위 제한 종류

  1. 제네릭 클래스의 타입 제한
    • 상위 경계 (Upper Bound)를 사용하여 제한할 수 있습니다. 상위 경계 (Upper Bound) : extends 키워드를 사용하여 상위 클래스나 인터페이스를 제한합니다. 상위 경계를 설정하면 해당 클래스 또는 인터페이스와 그 자손 클래스들만이 타입 인자로 사용될 수 있습니다.
    • 타입 제한 기본 문법 구조 접근지정자 class 클래스명< T extends 상위클래스명> { / 타입 T를 사용한 코드 / } → 클래스 / 인터페이스 상관없이 항상 extends 사용 (인터페이스로 작성되었음에도 implements를 사용하지 않습니다.)
  2. 제네릭 메서드의 타입 제한
    • 제네릭 메서드의 타입 제한은 메서드에 전달되는 타입 인자의 범위를 제한하는 방법입니다.
      이를 통해 특정한 타입 또는 그 타입의 상위 또는 하위 타입만을 인자로 받을 수 있도록 제한할 수 있습니다.
    • 접근지정자<T extends 상위클래스명>T 메서드이름 (T t) {/ 부모 클래스의 메서드 사용 가능 /}
      (인터페이스로 작성되었음에도 implements를 사용하지 않습니다.)
  3. 일반 메서드인데 매개변수로서 제네릭을 사용할 때의 제네릭 클래스 타입제한
    • 메서드의 매개변수로 제네릭 클래스 객체가 오는 경우의 타입제한

 

✅ 제네릭 타입 범위 제한 예시 코드

 

        1. 특정 클래스를 상속받은 타입 제한
        T는 SomeClass 클래스 또는 그의 하위 클래스만을 인자로 받을 수 있습니다.
        public <T extends SomeClass> void methodName(T arg) {
            // 메서드 내용
        }

        2. 인터페이스를 구현한 타입 제한
        T는 SomeInterface 인터페이스를 구현한 타입만을 인자로 받을 수 있습니다.
        public <T implements SomeInterface> void methodName(T arg) {
            // 메서드 내용
        }

        3. 여러 개의 타입 제한을 조합
        T는 SomeClass 클래스를 상속받고 동시에 SomeInterface 인터페이스를 구현한 타입만을 인자로 받을 수 있습니다.
        public <T extends SomeClass & SomeInterface> void methodName(T arg) {
            // 메서드 내용
        }

 

하위 경계 (Lower Bound) : super 키워드를 사용하여 하위 클래스를 제한합니다. 하위 경계를 설정하면 해당 클래스와 그 상위 클래스들만이 타입 인자로 사용될 수 있습니다.

제한된 타입 파라미터 (Multiple Bounds) : 하나의 타입 파라미터에 대해 여러 개의 상위 경계를 지정할 수 있습니다. extends 키워드를 사용하여 여러 클래스나 인터페이스를 상위 경계로 지정할 수 있습니다.

 

🎈 제네릭(Genric)의 상속

  • 부모클래스가 제네릭인 경우 자식클래스 또한 제네릭 (부모의 제네릭 변수를 그대로 물려받음)
  • 하위 클래스에서 타입 매개변수에 대한 추가적인 제한이나 확장도 가능합니다. 예를 들어, 상위 클래스의 타입 매개변수를 상속받은 타입 매개변수로 제한하거나, 추가적인 타입 매개변수를 정의할 수도 있습니다.
728x90
반응형

 

제네릭(Generic)은 Java에서 도입된 기능으로 컬렉션 클래스나 메서드의 매개변수, 반환 타입 등을 일반화하는 방법을 제공하는 기능입니다. 제네릭은 클래스, 인터페이스, 메서드에서 사용할 수 있습니다. 클래스나 인터페이스에 제네릭을 적용하면 해당 클래스나 인터페이스의 필드, 메서드, 생성자에서 사용되는 타입을 일반화할 수 있습니다. 메서드에 제네릭을 적용하면 해당 메서드에서 사용되는 타입을 일반화할 수 있습니다.
제네릭은 자바에서 데이터 타입을 파라미터와(Parameterize) 할 수 있는 방법을 제공하는 프로그래밍 기법입니다.그 자체로 타입은 아니지만, 클래스나 인터페이스, 메서드를 정의할 때 사용하는 타입 매개변수를 가리킵니다.

 

https://www.youtube.com/@doit4312/playlists

 

제네릭은 Java 5부터 도입되었으며, 컴파일 시점에서 타입 체크가 이루어지기 때문에 타입 안정성을 보장하고 형변환을 줄일 수 있습니다. 또한, 제네릭을 사용하면 코드의 가독성도 높아지고 오류를 사전에 방지할 수 있습니다.
예로 들면, 제네릭을 사용하면 컬렉션에 저장되는 객체의 타입을 컴파일 시점에 체크할 수 있고, 타입 안정성을 보장받을 수 있습니다. 이를 통해 잘못된 타입의 객체를 저장하거나 꺼낼 때 발생하는 런타임 오류를 사전에 방지할 수 있습니다.

 

https://www.youtube.com/@doit4312/playlists

 

 

🎈 Generic 클래스 / 인터페이스 정의 문법 구조

  • 제네릭을 사용하기 위해서는 타입 매개변수를 선언해야 합니다. 타입 매개변수는 일반적으로 대문자로 표기하며, 클래스나 메서드에 선언됩니다. 제네릭 타입을 사용할 때에는 실제 타입으로 대체하여 사용하게 됩니다. 제네릭 클래스는 객체를 만들 때 타입이 정해집니다.

  • 일반적으로 <T>와 같이 꺽쇠(<>) 안에 대문자로 표현된 타입 매개변수를 사용합니다. 이후에 해당 타입 매개변수를 클래스의 필드, 메서드의 매개변수, 반환 타입 등에 사용하여 일반적인 코드를 작성할 수 있습니다. 실제 사용할 때는 타입 매개변수에 구체적인 타입을 지정하여 사용합니다. < > 꺽쇠 안에 작성되는 건 T, K , V 같은 변수이름을 작성하는데, 변수 이름이라 사용자가 마음대로 작성한 후 기입해도 되지만 일반적으로 영 대문자 하나를 사용합니다.


    ex) 제네릭 타입 변수명이 하나인 경우 
             접근지정자 class(또는 interface) 클래스명 <T> {
                       //타입 T를 사용한 코드
           }

     ▶   public class MyClass<T> { 
           //여기서의 T는 아직 정해지지 않았고, 이 후 어떤 타입을 작성하냐에 따라 달라집니다.
                  private T t;
                  public T get() {
                  return t;
              }
                  public void set (T t) {
                      this.t = t;
              }
      }



    ex) 제네릭 타입 변수명이 두개인 경우    
             접근지정자 class(또는 interface) 클래스명 <K, V> {
                       //타입 K, V를 사용한 코드
           }

     ▶   public interface MyInterface<K, V> { 
           //이 후, K와 V의 타입은 객체를 생성하면서 정해주려고 제네릭으로 선언해두었습니다.
                 public abstract void setKey( K k);
                 public abstract void setValue( V v);
                 public abstract void getKey( );
                 public abstract void setKey( );

           }

 

 

예를 들어, ArrayList 클래스는 제네릭을 사용하여 여러 종류의 객체를 저장할 수 있습니다. ArrayList<Integer>는 정수형 객체만을 저장할 수 있는 리스트를 의미하고, ArrayList<String>은 문자열 객체만을 저장할 수 있는 리스트를 의미합니다. 이렇게 제네릭을 사용하면 타입에 따라 다양한 종류의 리스트를 생성할 수 있습니다.

 

 

🎈 Generic 클래스 / 인터페이스 객체 생성 문법 구조

  • 객체 생성** 객체 생성 시 제네릭 타입을 지정하지 않으면 올 수 있는 Type 중 최상위 클래스(Object)로 인식 MyClass mc = new MyClass(); == MyClass<Object< mc = new MyClass<>(); 동일한 의미!
  • 클래스명<실제 제네릭 타입> 참조변수명 = new 클래스명<실제 제네릭 타입>(); or 클래스명 <실제 제네릭 타입 > 참조변수명 = new 클래스명<>(); → 생성자의 경우 내부의 타입 생략 가능

 

//T를 매개변수로 하는 제네릭 클래스 생성
class MyClass<T> {
	private T t;
	public T get() {
		return t;
	}
	public void set(T t) {
		this.t = t;
	}
}

public class Ex10_SingleGenericBasic {

	public static void main(String[] args) {

		MyClass	<String> mc1 = new MyClass<String>();
		mc1.set("안녕하세요");
		System.out.println(mc1.get());
		
		
		
		MyClass <Integer> mc2 = new MyClass<>(); //= 뒤의 Integer는 생략가능
		mc2.set(8);
		System.out.println("제 나이는 " + mc2.get() + "살입니다.");
		
		MyClass<Integer> mc3 = new MyClass<>();
		//mc3.set("안녕"); //강한 타입체크 Integer로 정해진 타입에 String 타입을 넣어서 바로 에러가 발생
	}

}

 

💡 제네릭의 기본 개념은 클래스 내에 사용되는 타입을 클래스가 정의될 때가 아닌 객체를 생성할 때 정의하겠다는 의미

 

🎈 Generic(제네릭) method(메서드)

 

제네릭 메서드는 일반 클래스안에 선언된 메서드 선언 시에 타입 매개변수를 사용하여 다양한 타입의 매개변수를 처리할 수 있도록 하는 기능입니다. 일반클래스 안에 만들어지기 때문에 클래스를 만드는 시점에서는 <T>를 정할 수 없고 메서드를 호출할 때, 제네릭 타입을 정할 수 있습니다. 단, 메서드의 매개변수 타입의 제네릭 변수가 사용된다면 반환 타입이나 매개변수의 타입에 일반적인 타입 대신 타입 매개변수를 사용하여 타입의 작성의 생략이 가능하는 등의 유연성을 제공합니다

  • 제네릭 메서드는 메서드 내에서 사용되는 타입 매개변수를 선언하여 메서드의 매개변수, 반환 값, 지역 변수 등에서 사용할 수 있도록 합니다.
  • 일반적으로 메서드의 시그니처에 <T>와 같은 형태로 타입 매개변수를 선언하며, 메서드 내에서 해당 타입을 사용할 수 있습니다.
  • 제네릭 메서드는 호출할 때 매개변수의 타입을 명시적으로 지정하거나, 컴파일러가 타입을 추론하여 암묵적으로 결정할 수 있습니다.

 

  • Generic 메서드 문법 예시
        public <T> void printArray(T[] array) {
            for (T element : array) {
                System.out.println(element);
            }
        }

        메서드의 타입 매개변수로 T를 사용하고 있습니다. 
        이제 T는 메서드 내부에서 사용할 수 있는 타입으로 간주됩니다.

        printArray 메서드는 배열을 받아서 배열의 모든 요소를 출력하는 역할을 합니다. 
        이때 배열의 타입은 제네릭 타입 T로 지정되어 있으므로, 어떤 타입의 배열이든지 처리할 수 있습니다. 
        예를 들어 Integer[], String[], Double[] 등을 인자로 전달할 수 있습니다.

        Integer[] intArray = { 1, 2, 3, 4, 5 };
        printArray(intArray); // Integer 배열을 출력

        String[] strArray = { "Hello", "World" };
        printArray(strArray); // String 배열을 출력
728x90
반응형

 

Spring Bean (스프링 빈)이란❓


Spring Bean은 Spring Framework에서 관리되는 객체를 의미합니다. 의존성 주입(Dependency Injection, DI)객체 간의 의존 관계를 개발자가 직접 관리하지 않고, 외부에서 의존하는 객체를 주입하여 사용하는 디자인 패턴입니다.
DI는 객체 간의 결합도를 낮추고 유연하고 재사용 가능한 코드를 작성할 수 있도록 도와줍니다.
Spring Framework은 의존성 주입(Dependency Injection)을 통해 객체들을 생성, 관리, 연결하는데, 이러한 객체들을 “Spring Bean”이라고 합니다.

Spring Bean은 일반적으로 자바 클래스로 표현되며, Spring 컨테이너(ApplicationContext)에 의해 생성되고 관리됩니다. Spring Bean은 개발자가 정의한 설정 파일(XML 또는 Java Config)에 기반하여 컨테이너에 등록됩니다. 컨테이너는 Spring Bean의 생명 주기를 관리합니다.

 

Spring Bean의 주요 특징:

  1. 스프링 컨테이너에 등록: Spring Bean은 스프링 컨테이너에 등록되어야 합니다. 등록된 Bean은 컨테이너에서 관리되고 필요한 곳에서 주입(Dependency Injection)되어 사용됩니다.

  2. 라이프사이클 관리: Spring 컨테이너는 Spring Bean의 라이프사이클을 관리합니다. Bean의 생성, 초기화, 소멸 등을 컨테이너가 담당합니다.

  3. 의존성 주입: Spring Bean은 의존성 주입(Dependency Injection)을 통해 다른 Bean과 연결됩니다. 이를 통해 객체 간의 결합도를 낮출 수 있고, 유연하고 재사용 가능한 애플리케이션을 만들 수 있습니다.

  4. 스코프: Spring Bean은 스코프에 따라 다르게 관리됩니다. 주요 스코프로는 Singleton, Prototype, Request, Session 등이 있으며, 각 스코프에 따라 Bean의 생성과 소멸 시점이 달라집니다.

  5. 어노테이션과 XML 설정: Spring Bean은 어노테이션을 사용하여 자동으로 등록할 수도 있고, XML 설정 파일을 통해 수동으로 등록할 수도 있습니다. 주로 XML 설정 방식은 과거에 사용되었으며, 현재는 주로 어노테이션을 사용하는 방식이 일반적입니다.

 

일반적으로 객체 간의 의존 관계는 하나의 객체가 다른 객체를 생성하거나 참조하여 사용하는 것으로 나타납니다. 이러한 의존 관계는 코드 내에서 강한 결합도를 만들어내고, 객체의 생성과 관리를 담당하는 클래스가 다른 객체들에 대한 정보를 갖고 있어야 한다는 문제를 발생시킵니다. 이로 인해 코드의 유연성과 재사용성이 저하되는 문제가 발생할 수 있습니다.

DI는 이러한 문제를 해결하기 위해 의존하는 객체를 외부에서 주입하는 방식을 채택합니다. 주입된 객체는 해당 객체가 필요한 시점에 사용됩니다. 주로 생성자(Constructor) 주입, Setter 주입, 인터페이스 주입 등의 방식을 사용합니다.

 

        package hello.hellospring.controller;


        import hello.hellospring.service.MemberService;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Controller;

        //스프링이 처음에 뜰 때, 스프링 컨테이너라는 박스가 생기는데 만약 그곳에 컨트롤러 애노테이션이 있으면 
	//MemberController객체를 생성해서 담아준 후 스프링 빈이 관리해줍니다.
        @Controller
        public class MemberController {

            1. DI(Dipendency Injection) 필드 주입 방식
            @Autowired private MemberService memberService();


            2.DI(Dipendency Injection) setter 방식
            private MemberService memberService;

            @Autowired
            public void setMemberService(MemberService memberService) {
                this.memberService = memberService;
            }


            3.DI(Dipendency Injection) 생성자 주입 방식

            private final MemberService memberService;

            @Autowired
            public MemberController (MemberService memberService) {
                this.memberService = memberService;
            }
        }

 

DI의 주요 이점은 다음과 같습니다:

  1. 결합도 감소: 객체 간의 의존 관계를 외부에서 관리하기 때문에 객체들 간의 결합도가 낮아집니다. 이로 인해 하나의 객체 수정이 다른 객체에 미치는 영향을 최소화하고, 코드의 유지 보수성이 향상됩니다.

  2. 재사용성과 확장성: DI를 통해 의존하는 객체를 외부에서 주입받기 때문에 해당 객체의 변경 없이 쉽게 다른 객체와 조합하여 재사용하거나 기능을 확장할 수 있습니다.

  3. 테스트 용이성: 의존 객체를 모의(Mock) 객체로 대체하여 단위 테스트를 수행할 수 있습니다. 의존 객체의 동작을 외부에서 주입하여 테스트를 진행할 수 있기 때문에 테스트 용이성이 높아집니다.

Spring Framework는 DI를 통해 객체 간의 의존 관계를 관리하고 주입하는 기능을 제공합니다.
이를 통해 Spring에서는 객체 지향적인 애플리케이션을 개발할 수 있으며, 유연하고 확장 가능한 코드를 작성할 수 있습니다.

 

 

이 링크를 통해 구매하시면 제가 수익을 받을 수 있어요. 🤗
인프런(김영한) - 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

https://inf.run/SGi5S

728x90
반응형

 

쓰레드의 생성방법은 크게 2가지가 있습니다. 어느 쪽을 선택해도 별 차이는 없지만 Thread 클래스를 상속받으면
다른 클래스를 상속받을 수 없기때문에, Runnable 인터페이스를 구현하는 방법이 일반적입니다.

Thread 클래스 상속 : java에서는 java.lang.Thread 클래스를 상속하여 쓰레드를 생성할 수 있습니다. Thread 클래스를 상속받은 사용자 정의 클래스를 만들고, run() 메서드를 오버라이딩하여 쓰레드가 실행할 작업을 정의합니다. 사용자 정의 클래스의 인스턴스를 생성한 후, statr( ) 메서드를 호출하여 쓰레드를 시작합니다.

 

     
     	//Thread class를 상속받아 run() 메서드 overrid한 클래스 정의( 또는 익명클래스)
        class MyThread extends Thread {
                @override 
            public void run() {
                // 쓰레드가 실행할 작업 정의
            }
        }

        // 쓰레드 객체 생성 및 실행
        MyThread thread = new MyThread(); 
        //또는 Thread thread = new Thread(); 
        //-> 이렇게 객체를 선언해도 어차피 Thread를 상속받은 상황이라 가능하다. 
        thread.start(); //statr()메서드를 이용하여 Thread 실행!

 

💡 Run() 메서드와 Start() 메서드

 

  1. run() 메서드 : run() 메서드는 Runnable 인터페이스나 Thread 클래스에서 구현해야 하는 메서드입니다. 쓰레드가 실행될 때 호출되는 메서드로, 쓰레드가 수행할 작업을 정의합니다. run() 메서드 내부에 작업의 로직을 구현하고, 이 메서드가 모두 실행되면 쓰레드의 실행이 종료됩니다. run() 메서드는 직접 호출하여 실행하는 것이 아니라, 쓰레드가 start() 메서드를 통해 실행될 때 내부적으로 호출됩니다.

  2. start() 메서드 : start() 메서드는 Thread 클래스에서 제공하는 메서드로, 쓰레드를 시작하는 역할을 합니다. start() 메서드를 호출하면, 쓰레드는 자신의 run() 메서드를 실행하기 위해 준비되고 , 내부적으로 새로운 실행 흐름을 만들고, 쓰레드가 독립적으로 실행될 수 있도록 준비를 합니다. start() 메서드를 호출한 후에는 별도의 작업이나 제어 없이 쓰레드가 자동으로 실행됩니다. start() 메서드는 한 번만 호출할 수 있습니다. 동일한 쓰레드에 대해 start() 메서드를 다시 호출하면 예외가 발생합니다.

 

Runnable 인터페이스 구현 : java에서는 java.lang.Runnable 인터페이스를 구현하여 쓰레드를 생성할 수 있습니다. Runnable 인터페이스를 구현한 사용자 정의 클래스를 만들고, 내부적으로 Runnable 객체의 run() 메서드를 구하여 쓰레드가 실행할 작업을 정의합니다.
사용자 정의 클래스의 인스턴스를 생성한 후 , Thread 클래스의 생성자에 Runnable 인터페이스를 구현한 객체를 전달합니다. Thread 클래스의 인스턴스의 start( ) 메서드를 호출하여 쓰레드를 시작합니다.

        class MyRunnable implements Runnable { 
        //Runnable interface를 구현한 클래스를 정의함
        //Runnable = Run()의 기능을 정의한 인터페이스(객체)
                @override
            public void run() {
                // 쓰레드가 실행할 작업 정의
            }
        }

        //Runnable  객체 생성 -> Threade 객체 생성 (생성자에 Runnable 객체를 전달)
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);

        //start() 메서드를 이용하여 Thread를 실행
        thread.start();

🚫 재정의한 메서드는 run() 이지만 Thread의 실행은 start() 메서드를 호출!

🚫 Thread 객체는 재사용 할 수 없습니다. ( → 하나의 객체는 한번만 start()가 가능합니다.)

🎈 익명 이너 클래스를 쓰레드 생성에 사용하기


익명 이너 클래스(Anonymous Inner Class)는 이름이 없는 내부 클래스로, 클래스를 정의하면서 동시에 인스턴스를 생성하는 방법입니다.
익명 이너 클래스를 사용하면 스레드에서 직접적으로 클래스를 정의하고 인스턴스를 생성할 수 있으므로, 코드의 간결성과 가독성을 높일 수 있습니다.
주로 간단한 작업이나 임시적인 스레드 생성에 활용됩니다.

        
        Thread thread = new Thread() {
            public void run() {
                // 스레드에서 실행할 코드 작성
            }
        };


        Runnable runnable = new Runnable() { 
        //인터페이스의 객체도 익명이너클래스를 사용하게되면 하위클래스를 직접 만들지 않아도 바로 생성이 가능함
        //new Runnable() { }의 중괄호 안에 미완성인 method run() 메서드를 overriding 하여 전부 기입하여 넘겨주었습니다.  
          public void run() {
                // 스레드에서 실행할 코드 작성
            }
        };

        Thread thread = new Thread(runnable);

 

🎈 Thread의 속성 ( Thread 객체 가져오기 / 이름 / Thread 개수 / 우선순위 / 데몬설정)


currentThread() 메서드 : Thread 클래스의 currentThread() 정적 static 메서드는 현재 실행 중인 쓰레드를 반환하는 정적 메서드입니다. 이 메서드를 호출하면 현재 실행 중인 쓰레드의 참조를 얻을 수 있습니다. 보통 currentThread() 메서드는 다중 쓰레드 환경에서 현재 실행 중인 쓰레드의 정보를 얻기 위해 사용됩니다. 이를 통해 각 쓰레드의 동작을 구분하거나, 특정 작업을 현재 쓰레드에서만 수행할 수 있도록 조건을 검사하는 등의 용도로 활용될 수 있습니다.
static Thread Thread.currentThread() → Thread 참조 객체가 없는 경우에 사용

 

        public class CurrentThreadExample {
            public static void main(String[] args) {
                Thread currentThread = Thread.currentThread(); // 현재 실행 중인 쓰레드 얻기
                System.out.println("현재 실행 중인 쓰레드: " + currentThread.getName());
            }
        }
728x90

+ Recent posts