인텔리제이로 도커 컴포즈 올리는 중에

error during connect: Get "http://%2F%2F.%2Fpipe%2FdockerDesktopLinuxEngine/v1.47/containers/json?all=1&filters=%7B%22label%22%3A%7B%22com.docker.compose.config-hash%22%3Atrue%2C%2 2com.docker.compose.oneoff%3DFalse%22%3Atrue%2C%22com.docker.compose.project%3Dmybankpay%22%3Atrue%7D%7D": open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified.

이런 에러 발생...

 

 

관리자 권한으로 명령 프롬포트 들어가서 

cd "C:\Program Files\Docker\Docker"
DockerCli.exe -SwitchDaemon

실행 후 인텔리제이 껐다가 다시 들어가보기

addFirstDeque(Double-Ended Queue) 인터페이스에서 제공되는 메서드로, 요소를 큐의 맨 앞에 추가하는 기능을 한다.
Deque는 양쪽 끝에서 삽입과 삭제가 가능한 자료구조로, addFirst 메서드는 큐의 앞쪽에서 요소를 삽입할 수 있게 한다.

addFirst의 특징과 사용법

  • addFirst 메서드는 맨 앞에 요소를 추가하기 때문에, 다음 번에 큐에서 요소를 꺼낼 때 addFirst로 추가한 요소가 먼저 처리된다.
  • addFirst는 일반적인 큐의 FIFO(First-In-First-Out) 동작 방식과 다르게 동작하여, 우선적으로 처리해야 하는 요소가 있을 때 이를 맨 앞에 추가하여 우선 탐색할 수 있도록 한다.
  • addLast 또는 add 메서드는 큐의 맨 뒤에 요소를 추가하여 일반적인 큐처럼 먼저 들어온 요소가 먼저 나가는 순서로 처리된다!!!

Deque 인터페이스와 addFirst의 동작 방식

  • Deque 인터페이스는 양쪽에서 삽입과 삭제가 가능한 자료구조로, ArrayDequeLinkedList와 같은 클래스가 이를 구현하는 형태
  • addFirst는 큐의 맨 앞에 요소를 추가하여, 큐의 맨 앞부터 탐색을 진행할 수 있도록 하는 구조를 형성한다.

addFirstaddLast의 차이점

  1. addFirst:
    • 큐의 맨 앞에 요소를 추가하는 방식
    • 이를 통해 poll()을 호출할 때 가장 먼저 제거되는 요소가 될 수 있는 구조
    • 우선적으로 처리해야 하는 요소가 있을 때 유용한 방식
  2. addLast (== add):
    • 큐의 맨 뒤에 요소를 추가하는 방식임
    • 먼저 들어온 요소가 먼저 처리되는 FIFO 구조를 따르는 방식
    • 일반적인 큐 동작에서 순차적인 탐색을 제공하는 방식

addFirst가 사용되는 상황

  1. 우선순위가 있는 BFS 탐색:
    • BFS에서는 모든 경로를 동일한 우선순위로 탐색하지만, 특정 조건을 먼저 처리해야 할 때 addFirst를 사용하여 해당 작업을 큐의 맨 앞에 추가하여 탐색을 우선 처리하는 방식 (ex.순간 이동이 X+1이나 X-1보다 비용이 낮을 때, addFirst로 순간 이동을 큐 앞에 추가하여 먼저 탐색하도록 할 수 있다.)
  1. 다익스트라 알고리즘의 변형:
    • 특정 작업에 대해 비용이 0이거나 낮은 경우, 이 작업을 우선 처리하기 위해 addFirst를 활용하여 PriorityQueue 없이 다익스트라 방식으로 효율적인 탐색을 진행하는 구조 (ex. 특정 작업에 대해 비용이 0이거나 낮은 경우, 이를 우선적으로 큐 앞에 추가하여 먼저 처리하는 방식으로 addFirst를 사용할 수 있다,)

예제 코드

import java.util.ArrayDeque;
import java.util.Deque;

public class AddFirstExample {
    public static void main(String[] args) {
        Deque<Integer> deque = new ArrayDeque<>();

        // addFirst를 사용하여 요소를 큐 맨 앞에 추가하는 방식
        deque.addLast(1); // [1]
        deque.addLast(2); // [1, 2]
        deque.addFirst(0); // [0, 1, 2]

        System.out.println(deque.poll()); // 출력: 0, 가장 앞의 요소 제거 후 [1, 2]가 남는 구조
    }
}

이 예제에서 addFirst는 큐의 맨 앞에 요소를 삽입하여, poll()로 가장 먼저 꺼내지는 요소가 되는 구조임. addFirst를 통해 우선적으로 처리해야 하는 상황에서 가장 먼저 탐색할 수 있는 구조를 제공할 수 있음.

요약

  • addFirstDeque의 맨 앞에 요소를 추가하여, 해당 요소가 큐에서 먼저 처리되도록 할 수 있는 구조임
  • 우선적으로 탐색해야 하는 요소가 있을 때 유용하며, 특히 BFS 탐색에서 특정 조건의 경로를 우선 처리하고자 할 때 자주 사용되는 방식

addFirst를 적용한 코테 문제!!!! 13549번 사다리 조작

'공부 > Java' 카테고리의 다른 글

final 키워드  (0) 2024.10.26
외부 클래스 접근하기  (0) 2024.10.26
추상클래스와 상속관계 Q&A  (0) 2024.10.26
접근제어자  (0) 2024.10.26
멤버 변수와 프로퍼티  (0) 2024.10.26

 BFS (너비 우선 탐색)

  • BFS는 모든 경로를 동일한 깊이에서 탐색하며, 주로 최단 거리나 최소 비용을 구하는 문제에서 유용함
  • BFS는 를 사용해 구현하며, 시작 노드에서 목표 노드까지 가장 짧은 거리를 찾는 경우가 많다.

 BFS를 사용하는 경우

1. 최단 경로 문제

  • 시작 지점에서 목표 지점까지 가장 빠른 경로를 찾을 때 BFS를 사용한다.
  • BFS는 경로의 모든 노드를 같은 깊이에서 탐색하기 때문에, 최단 경로를 가장 먼저 찾을 수 있다.
  • 예시: 미로 탈출, 그래프의 두 노드 사이의 최단 경로 찾기, 최소 이동 횟수 구하기

2. 최소 비용 문제

  • 이동 시 비용이 일정한 경우 최단 경로처럼 최소 비용으로 특정 지점에 도달할 수 있다. 
  • 이때도 BFS는 가장 먼저 발견된 해가 최단이므로 적합하다.
  • 예시: 게임에서 목표 지점까지 최소 비용으로 도달하는 경로 찾기

3. 계층적 구조 탐색

  • 동일한 깊이에 있는 노드들을 먼저 탐색해야 할 때 유용하다.
  • 예시: 트리의 레벨 순회(예: 이진 트리의 각 레벨의 값을 차례로 출력)

 BFS의 특징

- 큐 사용: FIFO 방식으로 탐색해 모든 경로를 같은 깊이에서 탐색
- 최단 경로 탐색에 적합: 먼저 발견한 경로가 최단 경로이므로 최단 시간 안에 답을 찾는다.

 

 DFS (깊이 우선 탐색)

  • 한 경로를 끝까지 탐색한 후 다른 경로로 이동하는 방식
  • DFS는 스택(또는 재귀)을 사용해 구현하며, 특정 조건을 만족하는 모든 경로를 탐색하거나, 특정 경로가 존재하는지 확인하는 경우에 유용하다.

 DFS를 사용하는 경우

1. 모든 경로 또는 경우의 수 탐색: 

  • 특정 조건을 만족하는 모든 경로를 찾거나, 경우의 수를 세어야 할 때 DFS가 적합하다.
  • 예시: 경로 탐색(그래프에서 시작점에서 도착점까지의 모든 경로 찾기), 순열과 조합 문제, 미로의 모든 경로 찾기

2. 해당 경로 존재 여부 확인

  • 특정 경로가 존재하는지 여부만을 확인할 때 유용
  • DFS는 깊이 우선으로 탐색하기 때문에 경로의 존재 유무를 빠르게 파악할 수 있습니다.
  • 예시: 그래프에서 A에서 B로 가는 경로가 있는지 확인, 특정 패턴을 찾는 문제(예: 특정 문자열이 매트릭스 내에 존재하는지 확인)

3. 트리의 순회(Pre-order, In-order, Post-order)

  • 트리 구조에서의 탐색은 DFS를 통해 간단하게 구현할 수 있다.
  •  예시: 이진 트리의 전위/중위/후위 순회

 DFS의 특징

- 스택 또는 재귀 사용: 재귀적으로 깊이 우선 탐색을 진행
모든 경우의 수 탐색에 적합: 모든 경로를 끝까지 탐색하기 때문에 최적화되지 않은 문제에도 적합하다.
- 경로 존재 확인에 적합: 특정 경로가 존재하는지만 확인할 경우 DFS는 빠르게 탐색을 끝낼 수 있다.

 

 

문제 예시

 문제 유형 탐색 방식 이유  
최단 경로 찾기 BFS 가장 먼저 발견된 경로가 최단 경로이기 때문에 효율적
최소 이동 횟수 계산  BFS 같은 깊이의 노드를 순차적으로 탐색하여 최소 이동 경로를 찾음
특정 경로가 존재하는지 확인 DFS 깊이 우선으로 탐색하여 빠르게 경로 존재 여부를 파악
모든 경로 또는 경우의 수 탐색  DFS 재귀적으로 모든 가능한 경우의 수를 탐색하여 조건에 맞는 해를 찾음
트리의 전위, 중위, 후위 순회 DFS 트리의 깊이를 우선 탐색하기 위해 적합
 

백트래킹과 DFS의 차이점

  • DFS는 모든 경로를 탐색하면서 특정 조건을 찾거나, 경로의 존재 여부를 파악하는 데 주로 사용된다.
  • 백트래킹은 조건을 만족하지 않는 경로를 중간에 가지치기하여 탐색 공간을 줄이고 효율성을 높이는 것이 목적이다. 모든 경우의 수를 탐색하되, 불필요한 경우는 미리 배제하는 방식

 

 

BFS최단 거리, 최소 비용, 빠른 시간 구할때 사용!!! 주로 가 사용됨 ☞ 표문제가 나오면 BFS로 문제 적용해보자  ※ BFS는 모든 경로를 동일한 깊이에서 탐색하기 때문에 가장 먼저 목표에 도달하는 경로가 가장 짧은 경로다!!!

DFS모든 경우 탐색, 특정 경로 존재 여부 구할때 사용!!! 주로 스택재귀가 사용됨 ☞ 그래프 문제 나오면 DFS로 문제 적용해보자

백트래킹= DFS+가지치기

1. final 클래스

final이 클래스에 붙는 경우, 이 클래스는 상속이 불가능하다는 의미

즉, 이 클래스는 더 이상 하위 클래스를 만들 수 없다.

public final class MyFinalClass { 
	// 이 클래스는 상속될 수 없음 
}
  • String 클래스가 final로 선언되어 있기 때문에 String 클래스를 상속받아 새로운 클래스를 만들 수 없다.
  • 왜? final로 선언된 클래스는 상속을 막아 클래스의 동작을 보장하고자 할 때 사용됨

2. final 메서드

메서드에 final이 붙으면, 이 메서드는 재정의(overriding) 될 수 없다.

즉, 자식 클래스가 이 메서드를 재정의하여 다른 동작을 수행하지 못하도록 제한하는 역할을 함

public class ParentClass { 
	public final void show() { 
    	System.out.println("This is a final method."); 
    } 
}
  • show() 메서드가 final로 선언되었기 때문에, 이 메서드를 상속받는 클래스는 show() 메서드를 재정의할 수 없다.

3. final 변수 (상수)

변수에 final이 붙으면 값을 한 번만 할당할 수 있으며, 그 이후에는 변경할 수 없다.

즉, 상수처럼 동작하게 됨

public class Constants { 
	public static final int MAX_VALUE = 100; // 상수
}
  • final이 붙은 변수는 한 번 초기화된 이후 변경되지 않으므로, 상수처럼 사용된다.
  • 상수는 값이 변하지 않으며, 고정된 값을 의미

4. final 필드 (참조형 변수)

참조형 변수(객체)에 final이 붙으면, 그 참조 자체를 변경할 수 없다는 의미

즉, 해당 객체가 다른 객체를 가리키지 못하게 하지만, 참조하고 있는 객체의 내부 상태는 변경할 수 있다.

public class FinalExample { 
	public final List<String> list = new ArrayList<>(); 
    	public void modifyList() { 
    	list.add("Hello"); // 리스트에 요소 추가 가능 
        // list = new ArrayList<>(); // 오류: 참조 자체를 변경할 수 없음 
	} 
}
  • list 변수는 final로 선언되었기 때문에 다른 리스트로 교체할 수 없지만, 그 리스트의 내용을 수정하는 것은 가능하다.

final 참조형 변수는 상수가 아님

참조형 변수에 final이 붙어도 객체 자체는 변경할 수 없지만, 그 내부 상태는 변경 가능하므로 상수라고 볼 수는 없음!

 

결론:

  • final 클래스: 상속 불가
  • final 메서드: 재정의 불가
  • final 변수: 한 번 초기화되면 변경할 수 없는 상수
  • final 참조형 변수: 참조 자체는 변경할 수 없지만, 참조하는 객체의 내부 상태는 변경 가능

'공부 > Java' 카테고리의 다른 글

Deque의 addFirst메서드  (0) 2024.11.07
외부 클래스 접근하기  (0) 2024.10.26
추상클래스와 상속관계 Q&A  (0) 2024.10.26
접근제어자  (0) 2024.10.26
멤버 변수와 프로퍼티  (0) 2024.10.26

상황: A 클래스에서 B클래스 멤버변수와 메서드 접근하는 방법 구하기

 

1. 객체 생성

A 클래스 내부에서 직접 B 객체를 생성

public class A {
    public void useB() {
        B b = new B();  // B 클래스 객체 생성
        b.someMethod(); // B 클래스의 메서드 호출
        System.out.println(b.someField); // B 클래스의 멤버 변수 접근
    }
}

A 클래스가 독립적으로 B의 객체를 사용할 때 적합하다.(상속관계 X)

 

2. 생성자 주입 (Constructor Injection)

 

A의 생성자를 통해 B 객체를 주입받아 사용

public class A {
    private final B b;

    public A(B b) {  // 생성자 주입
        this.b = b;
    }

    public void useB() {
        b.someMethod();
    }
}

의존성 주입(DI) 방식 중 하나로, B 객체가 외부에서 주입되므로 A 클래스가 더 유연해진다.

 

3. 세터 주입 (Setter Injection)

세터 메서드를 통해 B 객체를 주입받아 사용
public class A {
    private B b;

    public void setB(B b) {  // 세터 주입
        this.b = b;
    }

    public void useB() {
        if (b != null) {
            b.someMethod();
        }
    }
}

주입받는 객체가 선택적일 때 유용함

4. 상속 (Inheritance)

 

A 클래스가 B 클래스를 상속하여 부모의 기능을 확장 및 사용

public class B {
    public void someMethod() {
        System.out.println("B 클래스의 메서드");
    }
}

public class A extends B {
    public void useB() {
        someMethod();  // B 클래스의 메서드 직접 호출
    }
}

A와 B가 "is-a" 관계일 때 적합하며, 상속을 통해 기본 기능을 확장할 수 있다.

is-a 관계: 자식 클래스가 부모 클래스의 일종으로 간주될 수 있는 관계로, 상속을 통해 성립됨

 

 

상속의 기본 목적은 재사용보다는 확장성과 유연성을 위한 설계!!

상속은 단순히 부모 클래스의 기능을 그대로 사용하는 것보다, 부모의 기능을 기반으로 확장하여 자식 클래스에 맞는 새로운 동작을 정의하는 데 목적이 있다! 

 

5. 인터페이스 사용

인터페이스를 통해 B 객체의 기능에 접근 (유연한 설계 가능)

public interface BInterface {
    void someMethod();
}

public class B implements BInterface {
    public void someMethod() {
        System.out.println("B 클래스의 메서드");
    }
}

public class A {
    private BInterface b;

    public A(BInterface b) {
        this.b = b;
    }

    public void useB() {
        b.someMethod();
    }
}

결합도를 낮추고 클래스 간 관계를 유연하게 만든다.

 

 

'공부 > Java' 카테고리의 다른 글

Deque의 addFirst메서드  (0) 2024.11.07
final 키워드  (0) 2024.10.26
추상클래스와 상속관계 Q&A  (0) 2024.10.26
접근제어자  (0) 2024.10.26
멤버 변수와 프로퍼티  (0) 2024.10.26

제가 자주 헷갈리는 부분을 자체 Q&A로 정리해봤습니다(꾸벅)

 

Q: 추상 클래스에 추상 메서드가 없을 경우, 자식 클래스에서는 구현할 메서드가 없는가?

A:

  • 추상 클래스에 추상 메서드가 없을 경우, 자식 클래스는 추상 메서드를 구현할 필요가 없다.
  • 추상 클래스는 추상 메서드를 포함하지 않을 수 있으며, 그 경우 자식 클래스는 상속만 받고 추가로 구현해야 할 메서드는 없다.

Q. 추상 클래스에 있는 abstract 키워드가 붙은 메서드는 반드시 자식 클래스에서 구현해야 하는가?

A:

  • 추상 클래스에 있는 추상 메서드(abstract 메서드)는 자식 클래스에서 반드시 구현해야 한다.
  • 자식 클래스가 모든 추상 메서드를 구현하지 않으면, 자식 클래스도 추상 클래스가 되어야 한다.

Q. 추상 클래스가 멤버 변수를 가질 수 있는가? 자식 클래스에서 이를 사용할 수 있는가?

A:

  • 추상 클래스는 멤버 변수를 가질 수 있으며, 자식 클래스는 상속받아 사용할 수 있다.
  • 자식 클래스는 상속된 멤버 변수를 그대로 사용할 수 있으며, 상속의 재사용성을 활용할 수 있다.

Q. 추상 클래스에 생성자가 있을 경우, 자식 클래스는 부모 생성자를 호출해야 하는가?

A:

  • 추상 클래스도 생성자를 가질 수 있다.
  • 자식 클래스는 부모 클래스의 생성자를 반드시 호출해야 하며, 추상 클래스여도 동일하다.
  • 부모 클래스에 기본 생성자가 없고 매개변수가 있는 생성자만 있을 경우, 자식 클래스에서 부모 생성자를 명시적으로 호출(super)해야 한다.

Q. 부모 클래스에 매개변수가 있는 생성자가 있을 경우, 자식 클래스에서 부모 생성자를 호출하지 않으면 어떻게 되는가?

A:

  • 부모 클래스에 매개변수가 있는 생성자만 있고, 기본 생성자가 없을 경우, 자식 클래스는 부모 생성자를 명시적으로 호출해야 한다.
  • 만약 부모 생성자를 호출하지 않으면, 자바는 부모 클래스의 기본 생성자를 호출하려고 시도하다가 컴파일 에러가 발생한다.

Q. 상속 관계에서 자식 클래스는 부모 클래스의 생성자를 반드시 호출하여 초기화해야 하는가?

A:

  • 상속 관계에서는 자식 클래스의 생성자가 부모 클래스의 생성자를 호출하여 부모 클래스의 상태를 초기화해야 한다.
  • 부모 클래스가 추상 클래스일지라도, 자식 클래스에서 부모 생성자를 반드시 호출해야 하며, 그렇지 않으면 컴파일 에러가 발생한다.

전체적인 결론:

  • 추상 클래스는 추상 메서드가 없어도 상속할 수 있으며, 추상 메서드가 있을 경우 자식 클래스는 이를 반드시 구현해야 함
  • 추상 클래스는 생성자와 멤버 변수를 가질 수 있으며, 자식 클래스는 이를 상속받아 사용할 수 있음
  • 상속 관계에서는 자식 클래스의 생성자가 부모 클래스의 생성자를 반드시 호출하여 부모 클래스의 상태를 초기화해야 함
  • 부모 클래스에 매개변수가 있는 생성자만 있을 경우, 자식 클래스는 부모의 생성자를 명시적으로 호출해야 하며, 그렇지 않으면 컴파일 에러가 발생함

'공부 > Java' 카테고리의 다른 글

final 키워드  (0) 2024.10.26
외부 클래스 접근하기  (0) 2024.10.26
접근제어자  (0) 2024.10.26
멤버 변수와 프로퍼티  (0) 2024.10.26
iterator  (0) 2024.10.25

public

  • 모든 곳에서 접근가능하다. 
  • 같은 패키지, 외부 패키지, 같은 클래스, 상속받은 클래스  다 가능

protected

  • 같은 패키지에서 접근할 수 있고, 다른 패키지의 상속관계에서 접근이 가능하다.
  • 같은 패키지, 같은 클래스, 다른 패키지의 상속받은 클래스 가능

default(기본)

  • 같은 패키지 내에서만 접근가능하다.
  • 같은 패기지 가능 다른패키지 접근 불가

private

  • 같은 클래스 내에서만 접근가능하다. 
  • 같은 패키지, 다른 클래스 ,상속받은 클래스 다 접근 불가
접근 제어자 접근 제어자 같은 패키지 다른 패키지의 하위 클래스 다른 패키지
public 가능 가능 가능 가능
protected 가능 가능 가능 불가능
default 가능 가능 불가능 불가능
private 가능 불가능 불가능 불가능

'공부 > Java' 카테고리의 다른 글

외부 클래스 접근하기  (0) 2024.10.26
추상클래스와 상속관계 Q&A  (0) 2024.10.26
멤버 변수와 프로퍼티  (0) 2024.10.26
iterator  (0) 2024.10.25
추상클래스와 인터페이스  (0) 2024.10.25

멤버 변수(Member Variable)

클래스에 정의된 변수로, 객체의 속성이나 상태를 나타낸다.

프로퍼티(Property)

멤버 변수와 이를 다루는 getter/setter 메서드를 함께 포함한 개념으로, 객체의 특정 속성을 의미한다.

 

예시 코드

public class Person {
    // 멤버 변수 (혹은 프로퍼티)
    private String name;

    // getter 메서드
    public String getName() {
        return name;
    }

    // setter 메서드
    public void setName(String name) {
        this.name = name;
    }
}

 

 

내가 이해한 내용

멤버변수는 클래스 내에 정의된 변수. 객체의 상태나 속성을 나타냄

프로퍼티는 멤버변수를 getter/setter메서드로 접근할때 '프로퍼티'라 불림 →프로퍼티는 캡슐화된 멤버 변수다!

 

 

 

※캡슐화란?

  • 데이터를 보호하고 외부로부터 은닉하는 개념
  • 멤버 변수를 private으로 선언하고 getter/setter  메서드를 통해 접근하는 방식이 대표적인 캡슐화 방식임
  • 캡슐화를 토해 데이터의 무결성을 유지하고 외부로부터 객체의 내부 구현을 보호할 수 있음

'공부 > Java' 카테고리의 다른 글

추상클래스와 상속관계 Q&A  (0) 2024.10.26
접근제어자  (0) 2024.10.26
iterator  (0) 2024.10.25
추상클래스와 인터페이스  (0) 2024.10.25
트랜잭션(Transaction)과 커밋(Commit)  (0) 2024.10.18
  • Iterator는 컬렉션(예: 리스트, 집합 등)에서 요소들을 순차적으로 반복하면서 접근할 때 사용되는 인터페이스
  • Iterator를 사용하는 주된 이유는 컬렉션의 내부 구조에 상관없이 요소를 하나씩 처리할 수 있도록 하기 때문이다.
  • 컬렉션의 구조를 몰라도 일관된 방식으로 데이터를 처리할 수 있는 이점이 있다.

1. Iterator를 사용하는 이유

  • 컬렉션 요소 순회 (iteration): Iterator는 컬렉션에 저장된 요소들을 순차적으로 접근하고, 이를 하나씩 처리할 수 있게 한다.
  • 컬렉션의 내부 구현에 독립적: 리스트, 집합, 맵 등 서로 다른 자료구조가 있더라도, Iterator는 이러한 자료구조의 내부 구현을 신경 쓰지 않고 요소들을 반복 처리할 수 있다.
  • 삭제 기능 제공: Iterator는 순회 중에 요소를 안전하게 삭제할 수 있는 기능을 제공한다.→ ConcurrentModificationException 같은 문제를 피할 수 있다.
  • 코드 간결화: Iterator를 사용하면 반복문에서 컬렉션 요소에 접근하는 코드를 간결하게 작성할 수 있다.

2. Iterator의 주요 메서드

  • hasNext(): 다음 요소가 있으면 true, 없으면 false를 반환
  • next(): 다음 요소를 반환하고, 반복자를 다음 요소로 이동시
  • remove(): 현재 반복자 위치의 요소 삭제 (선택적으로 구현될 수 있음)

3. Iterator 사용 예시

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");

        // Iterator 생성
        Iterator<String> iterator = fruits.iterator();

        // Iterator를 사용하여 컬렉션 순회
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            System.out.println(fruit);
        }
    }
}

 

4. Iterator의 장점

  • 컬렉션의 일관된 순회 방식: ArrayList, HashSet, TreeSet과 같은 다양한 컬렉션 클래스에서 요소들을 순회할 때, 각각의 자료구조에 맞는 구현을 신경 쓰지 않고 Iterator 인터페이스를 사용해 일관된 방식으로 순회할 수 있다.
  • 동적 삭제 가능: Iterator는 순회 중간에 컬렉션에서 요소를 안전하게 삭제할 수 있는 기능을 제공한다.
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
    String fruit = iterator.next();
    if (fruit.equals("Banana")) {
        iterator.remove();  // Banana 삭제
    }
}

 

5. for-each와의 차이

  • for-each는 순회만 할 수 있고, remove() 같은 기능은 사용할 수 없다.
  • for-each는 내부적으로 Iterator를 사용하지만, 이를 명시적으로 사용할 수 없고 요소 삭제는 지원하지 않는다.

6. Iterator vs ListIterator

  • ListIterator: Iterator의 확장된 버전으로, 양방향 순회(앞으로도, 뒤로도 순회 가능) 및 요소 수정 기능을 추가로 제공한다.
  • List와 같은 양방향 구조를 다룰 때 유용함

대표적인 컬렉션 클래스

1. ArrayList

ArrayList는 동적 배열을 기반으로 하여, 인덱스를 이용한 순회와 Iterator 또는 for-each를 통한 순회를 지원한다.

 

ArrayList 순회 방법

import java.util.ArrayList;
import java.util.Iterator;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("Apple");
        arrayList.add("Banana");
        arrayList.add("Orange");

        // 1. for-each 문 사용
        System.out.println("Using for-each loop:");
        for (String fruit : arrayList) {
            System.out.println(fruit);
        }

        // 2. 일반 for 문 사용 (인덱스)
        System.out.println("\nUsing for loop with index:");
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.println(arrayList.get(i));
        }

        // 3. Iterator 사용
        System.out.println("\nUsing Iterator:");
        Iterator<String> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

 

2. HashSet

HashSet은 해시 테이블을 기반으로 하며, 요소의 삽입 순서를 보장하지 않음중복된 요소를 허용하지 않음이 특징

HashSet은 순서를 보장하지 않기(인덱스x) 때문에 for-each 또는 Iterator를 사용하여 순회합니다.

 

HashSet 순회 방법

import java.util.HashSet;
import java.util.Iterator;

public class Main {
    public static void main(String[] args) {
        HashSet<String> hashSet = new HashSet<>();
        hashSet.add("Apple");
        hashSet.add("Banana");
        hashSet.add("Orange");

        // 1. for-each 문 사용
        System.out.println("Using for-each loop:");
        for (String fruit : hashSet) {
            System.out.println(fruit);
        }

        // 2. Iterator 사용
        System.out.println("\nUsing Iterator:");
        Iterator<String> iterator = hashSet.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

 

3. TreeSet

TreeSet은 정렬된 순서로 요소를 유지하는 이진 탐색 트리 기반의 자료구조입니다. 삽입된 순서와 상관없이 요소들이 자동으로 정렬( 문자열은 사전순으로 정렬되며, 숫자는 오름차순으로 정렬 )되며, for-each와 Iterator로 순회할 수 있다.

 

TreeSet 순회 방법

import java.util.Iterator;
import java.util.TreeSet;

public class Main {
    public static void main(String[] args) {
        TreeSet<String> treeSet = new TreeSet<>();
        treeSet.add("Apple");
        treeSet.add("Banana");
        treeSet.add("Orange");

        // 1. for-each 문 사용
        System.out.println("Using for-each loop:");
        for (String fruit : treeSet) {
            System.out.println(fruit);
        }

        // 2. Iterator 사용
        System.out.println("\nUsing Iterator:");
        Iterator<String> iterator = treeSet.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

 

요약: 순회 방식 정리

  1. ArrayList:
    • for-each: 순서대로 순회 (삽입된 순서 유지)
    • 일반 for 문: 인덱스를 사용하여 순회
    • Iterator: 요소를 순서대로 순회
  2. HashSet:
    • for-each: 순서 없이 순회 (삽입 순서 보장하지 않음)
    • Iterator: 순서 없이 요소 순회
  3. TreeSet:
    • for-each: 정렬된 순서로 요소 순회
    • Iterator: 정렬된 순서로 순회

 

 

각 컬렉션 클래스(ArrayList, HashSet,TreeSet등 모든 컬렉션 프레임워크의 클래스)마다 순회 방식이 동일해 보여도 내부적으로는 순서와 중복 처리 방식이 다르다→ iterator는 컬렉션 클래스의 내부 구조와 상관없이 일관된 방식으로 요소를 순회한다!! 이게 뽀인뜨.

 
 

 

'공부 > Java' 카테고리의 다른 글

추상클래스와 상속관계 Q&A  (0) 2024.10.26
접근제어자  (0) 2024.10.26
멤버 변수와 프로퍼티  (0) 2024.10.26
추상클래스와 인터페이스  (0) 2024.10.25
트랜잭션(Transaction)과 커밋(Commit)  (0) 2024.10.18

 

1. 추상 클래스 (Abstract Class)

   정의
  • 추상 메서드를 포함할 수 있는 클래스
  • 추상 메서드는 구현이 없는 메서드로, 해당 클래스를 상속받는 자식 클래스에서 반드시 구현해야 한다.
  • 추상 클래스는 그 외에도 일반 메서드를 포함할 수 있다.
   사용 이유
  • 공통된 속성과 기능을 가진 클래스들 사이에서 코드 재사용을 목적으로 사용된다.
  • 기본적인 구현을 제공하면서, 일부 기능만 자식 클래스에서 다르게 구현할 수 있도록 한다.
   특징
     1. 추상 클래스는 일부 메서드를 구현할 수 있다.
     2. 멤버 변수와 생성자를 가질 수 있다.
     3. 단일 상속만 가능하다. 즉, 한 클래스는 하나의 추상 클래스만 상속할 수 있다.
     4. `abstract` 키워드를 사용하여 선언되며, 하나 이상의 추상 메서드를 포함할 수 있지만, 모든 메서드가 추상일 필요는 없다.
     
 
abstract class Animal {
    String name;

    // 추상 메서드 (구현 필요)
    abstract void sound();

    // 일반 메서드 (구현 제공)
    void eat() {
        System.out.println("Eating...");
    }
}

class Dog extends Animal {
    // 추상 메서드 구현
    @Override
    void sound() {
        System.out.println("Bark!");
    }
}

 

2. 인터페이스 (Interface)

 
정의
  • 인터페이스는 추상 메서드들의 모음
  • 인터페이스에 정의된 모든 메서드는 기본적으로 구현이 없고, 이를 구현하는 클래스가 모두 구현해야 한다.
  • 자바 8 이후로는 인터페이스에서도 디폴트 메서드(기본 구현을 가진 메서드)와 정적 메서드를 가질 수 있게 됨
사용 이유
  • 여러 클래스에서 공통된 행동을 정의하거나, 특정 기능을 강제하는 용도로 사용됨
  • 상속과 달리 다중 상속이 가능하므로 유연하게 사용할 수 있습니다.

특징
     1. 다중 구현이 가능  한 클래스는 여러 인터페이스를 동시에 구현할 수 있다.
     2. 인터페이스는 일반적으로 구현을 포함하지 않는 메서드를 정의(자바 8 이후로 디폴트 메서드 및 정적 메서드 사용 가능)
     3. 멤버 변수를 가질 수 없음 모든 필드는 기본적으로 `public static final`로 정의된다.
     4. 클래스와 달리 다중 상속이 가능하므로, 다양한 기능을 추가할 수 있다.
     
interface Animal {
    // 추상 메서드
    void sound();

    // 자바 8 이후의 디폴트 메서드
    default void eat() {
        System.out.println("Eating...");
    }
}

class Dog implements Animal {
    // 인터페이스 메서드 구현
    @Override
    public void sound() {
        System.out.println("Bark!");
    }
}
구분 추상 클래스   인터페이스
상속 가능성  단일 상속만 가능 (한 클래스는 하나의 추상 클래스만 상속 가능)  다중 구현 가능 (한 클래스가 여러 인터페이스를 구현할 수 있음) 
메서드 구현 여부 구현된 메서드와 추상 메서드를 모두 포함할 수 있음   자바 8 이전에는 모든 메서드가 추상 메서드, 자바 8 이후로 디폴트 메서드 가능
멤버 변수 멤버 변수 가질 수 있음 멤버 변수를 가질 수 없음 (필드는 `public static final`로 고정됨) 
생성자   생성자 가질 수 있음     생성자 가질 수 없음  
사용 목적  상태(멤버 변수)와 메서드를 공유하는 클래스들의 기본 기능 제공   클래스가 구현해야 할 기능(행동)을 정의하여 강제함  

 

4. 언제 무엇을 사용해야 할까?

 추상 클래스를 사용해야 할 때
     - 여러 클래스가 공통된 상태(필드)를 가져야 하며, 일부 메서드에 기본적인 구현이 필요할 때
     - 클래스를 상속받으면서 상속받은 기본 기능을 재사용하고 싶을 때
   
인터페이스를 사용해야 할 때
     - 여러 클래스에 특정 기능을 강제하고, 그 기능의 구현 방식은 각각 다를 때
     - 다중 상속이 필요한 경우
     - 상태가 필요 없고, 행동(메서드)만 정의할 때

 

Q&A

 

Q. 인터페이스의 메서드들은 반드시 상속받은 클래스에서 구현해야한다는거 맞지? 반면 추상 클래스를 상속받으면 추상클래스의 모든 추상메서드를 다 수현할 필요가 없고

 

A:

1. 인터페이스의 메서드 구현

  • 반드시 상속받은 클래스에서 구현해야 함: 인터페이스에 선언된 메서드들은 기본적으로 구현이 없기 때문에, 인터페이스를 구현하는 클래스는 반드시 그 메서드들을 구현해야 한다. (단, 자바 8 이후에는 디폴트 메서드를 사용하여 인터페이스 내에서도 일부 메서드에 기본 구현을 제공할 수 있다.)
interface Animal {
    void sound();  // 반드시 구현해야 하는 메서드
}

class Dog implements Animal {
    @Override
    public void sound() {
        System.out.println("Bark!");
    }
}

 

2. 추상 클래스의 메서드 구현

  • 모든 추상 메서드를 반드시 구현할 필요는 없음: 추상 클래스에는 추상 메서드뿐만 아니라 일반 메서드도 포함될 수 있다. 추상 메서드만 자식 클래스에서 반드시 구현해야 하며, 이미 구현된 일반 메서드는 자식 클래스에서 그대로 사용할 수 있다.
abstract class Animal {
    abstract void sound();  // 자식 클래스에서 구현해야 함
    
    void eat() {
        System.out.println("Eating...");  // 이미 구현된 메서드
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Bark!");
    }
    // eat() 메서드는 그대로 사용할 수 있음
}

 

 

Q. 멤버 변수는 추상클래스만 가질 수 있고, 인터페이스는 상수만 가질 수 있고 맞아?

 

A:

 

  • 추상 클래스멤버 변수를 가질 수 있다. 추상 클래스는 일반 클래스처럼 필드(멤버 변수)를 정의하고, 이를 자식 클래스에서 상속받아 사용할 수 있다.
  • 인터페이스상수(public static final 필드)만 가질 수 있습니다. 즉, 인터페이스에 정의된 변수는 항상 상수로 취급되며, 그 값을 변경할 수 없다.
// 추상 클래스
abstract class Animal {
    String name;  // 멤버 변수 (필드)
    
    abstract void sound();
}

// 인터페이스
interface AnimalInterface {
    static final int MAX_AGE = 100;  // 상수만 가질 수 있음
    
    void sound();
}

 

 

 

Q. 추상클래스에서 생성자를 가져?

A:  추상 클래스도 생성자를 가질 수 있다.

추상 클래스는 완전히 구현되지 않은 클래스이지만, 상속을 통해 자식 클래스에서 사용될 때 필요한 초기화를 위해 생성자를 정의할 수 있다. 다만, 추상 클래스 자체는 객체를 생성할 수 없기 때문에, 직접적으로 추상 클래스의 생성자를 호출하여 인스턴스를 만들 수는 없다. 자식 클래스가 추상 클래스를 상속할 때 부모 클래스인 추상 클래스의 생성자를 호출하여 초기화가 이루어질 수 있다.

abstract class Animal {
    String name;

    // 추상 클래스에도 생성자를 정의할 수 있음
    public Animal(String name) {
        this.name = name;
        System.out.println("Animal 생성자 호출됨");
    }

    // 추상 메서드
    abstract void sound();
}

class Dog extends Animal {
    
    // 자식 클래스에서 부모의 생성자를 호출
    public Dog(String name) {
        super(name);  // 부모 클래스(추상 클래스)의 생성자 호출
    }

    @Override
    void sound() {
        System.out.println(name + " says: Bark!");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Buddy");  // 자식 클래스의 객체 생성
        dog.sound();
    }
}

'공부 > Java' 카테고리의 다른 글

추상클래스와 상속관계 Q&A  (0) 2024.10.26
접근제어자  (0) 2024.10.26
멤버 변수와 프로퍼티  (0) 2024.10.26
iterator  (0) 2024.10.25
트랜잭션(Transaction)과 커밋(Commit)  (0) 2024.10.18

+ Recent posts