변수와 자료형(4)
1️⃣ 자료형에 대한 이해
1. List
자바 프로그래밍에서 List
는 일련의 요소를 저장하는 데 사용되는 순차적인 컬렉션을 나타냅니다.
이는 자바의 java.util.List
인터페이스를 통해 제공되며, 이는 주문된 컬렉션을 관리하기 위한 다양한 메소드를 제공합니다.
List
는 중복된 요소를 포함할 수 있고, 각 요소는 리스트 내에서 특정 위치를 가집니다.
사용자는 이 위치를 인덱스로 사용하여 리스트의 요소에 접근할 수 있습니다.
List
인터페이스의 주요 특징은 다음과 같습니다.
- 1. 순서 보장 : 리스트는 요소들이 추가된 순서를 유지하며, 각 요소는 특정 인덱스를 통해 접근할 수 있습니다.
- 2. 요소의 중복 허용 : 같은 값을 가진 요소를 여러 개 포함할 수 있습니다.
- 3. 동적 배열 : 리스트의 크기는 고정되어 있지 않고, 요소를 추가하거나 삭제함에 따라 동적으로 조절됩니다.
자바에서는 List
인터페이스를 구현하는 몇 가지 클래스가 있습니다.
가장 흔히 사용되는 구현체는 다음과 같습니다.
-
'ArrayList'
: 내부적으로 배열을 사용하여 요소를 저장합니다.- 요소의 추가와 인덱스를 통한 접근이 매우 빠르지만, 크기 조절이 필요할 때는 비용이 많이 들 수 있습니다.
-
'LinkedList'
: 각 요소가 다음 요소에 대한 참조와 함께 저장되는 연결 리스트를 사용합니다.- 요소의 추가와 삭제는 빠르지만, 인덱스를 통한 요소 접근은 시작부터 요소를 찾을 때까지 순차적으로 검색해야 하므로 시간이 더 걸립니다.
-
'Vector'
:'ArrayList'
와 비슷하지만, 다중 스레드 환경에서 안전하게 사용할 수 있도록 동기화된 메소드를 제공합니다.
📝 정리.
'List'
는 자바 컬렉션 프레임워크의 일부이며, 데이터를 관리하고 처리하는 데 매우 유용합니다.
프로그래머는 이러한 컬렉션을 사용하여 데이터를 유연하게 조작할 수 있습니다.
1.2 List의 주요 메서드.
자바의 'List'
인터페이스에는 여러 가지 중요한 메서드들이 포함되어 있으며, 이를 통해 리스트 내의 요소들을 조작하고 접근할 수 있습니다.
다음은 'List'
인터체이스에서 제공하는 몇 가지 주요 메서드들입니다.
-
'add(E e)'
: 리스트의 끝에 요소를 추가합니다. -
'add(int index, E element)'
: 지정된 위치에 요소를 삽입합니다. -
'addAll(Collection<? extends E> c)'
: 지정된 컬렉션의 모든 요소를 리스트의 끝에 추가합니다. -
'addAll(int index, Collection<? extends E> c)'
: 지정된 위치부터 컬렉션의 모든 요소를 리스트에 추가합니다. -
'clear()'
: 리스트에서 모든 요소를 제거합니다. -
'contains(Object o)'
: 리스트가 특정 요소를 포함하고 있는지 확인합니다. -
'get(int index)'
: 지정된 위치의 요소를 반환합니다. -
'indexOf(Object o)'
: 주어진 요소의 첫 번째 인덱스를 반환합니다. 요소가 리스트에 없는 경우 -1을 반환합니다. -
'lastIndexOf(Object o)'
: 주어진 요소의 마지막 인덱스를 반환합니다. 요소가 리스트에 없는 경우 -1을 반환합니다. -
'isEmpty()'
: 리스트가 비어 있는지 확인합니다. -
'iterator()'
: 리스트의 요소에 대한 반복자를 반환합니다. -
'listIterator()'
: 리스트의 요소를 리스트 순서대로 반복하는 리스트 반복자를 반환합니다. -
'remove(Object o)'
: 주어진 요소를 리스트에서 처음 발견되는 위치에서 제거하고, 그 결과를 반환합니다. -
'remove(int index)'
: 지정된 위치에 있는 요소를 리스트에서 제거하고, 그 요소를 반환합니다. -
'replaceAll(UnaryOperator<E> operator)'
: 주어진 연산자를 사용하여 리스트의 모든 요소를 대체합니다. -
'size()'
: 리스트에 있는 요소의 수를 반환합니다. -
'sort(Comparator<? super E> c)'
: 주어진 비교자를 사용하여 리스트를 정렬합니다. -
'subList(int fromIndex, int toIndex)'
: 지정된 범위의 부분 리스트를 반환합니다. -
'toArray()'
: 리스트 요소를 배열로 반환합니다.
📝 정리.
이 메서드들을 통해 리스트를 생성, 조회, 수정 및 관리하는 다양한 작업을 수행할 수 있습니다.
List
인터페이스를 사용함으로써 데이터를 효율적으로 처리하고 구조화할 수 있습니다.
2. Map
자바 프로그래밍에서 'Map'
은 키(key)와 값(value)의 쌍을 저장하는 객체입니다.
이는 키를 기반으로 빠르게 값을 검색할 수 있게 해주는 데이터 구조로, 각 키는 고유해야 합니다.(즉, 중복된 키를 가질 수 없습니다.)
'Map'
은 'java.util.Map'
인터페이스를 통해 정의되며, ‘HashMap
‘, ‘TreeMap
‘, ‘LinkedHashMap
‘ 등 다양한 구현체를 가집니다.
자바의 ‘Map
‘ 인터페이스는 키-값 쌍으로 데이터를 저장하고 관리하는 데 중점을 두는 데이터 구조로서, 특히 다음과 같은 주요 특징을 가지고 있습니다.
-
1. 키에 의한 값 접근 : ‘
Map
‘ 은 각 값에 고유한 키를 할당하며, 이 키를 사용하여 빠르게 해당 값을 검색할 수 있습니다.- 이는 데이터베이스의 인덱스와 유사한 방식으로 작동합니다.
-
2. 키의 유일성 : 맵 내에서 모든 키는 고유해야 합니다.
- 즉, 같은 키가 두 번 이상 존재할 수 없으며, 새로운 키-값 쌍을 추가할 때 이미 존재하는 키를 사용하면 기존의 값이 새 값으로 대체됩니다.
-
3. 값의 중복 허용 : 키는 유일해야 하지만 값은 중복될 수 있습니다.
- 다른 키가 동일한 값을 가리킬 수 있습니다.
-
4. 순서의 유무 : 일반적인 ‘
Map
‘ 구현체들은 키-값 쌍의 순서를 보장하지 않습니다.- 그러나 ‘
LinkedHashMap
‘ 과 같은 일부 구현체는 요소가 추가된 순서대로 반복할 수 있는 기능을 제공합니다. -
‘
TreeMap
‘ 은 키에 따라 정렬된 순서를 유지합니다.
- 그러나 ‘
-
5. 비동기화 및 동기화 : 기본적으로 대부분의 ‘
Map
‘ 구현체는 동기화되지 않습니다.(‘HashMap
‘). 이는 멀티 스레드 환경에서 동시 수정이 발생할 경우 안전하지 않을 수 있음을 의미합니다.- 반면에 ‘
Hashtable
‘ 과 같은 구현체는 기본적으로 동기화가 되어 있어 멀티 스레드 환경에서 안전합니다. - 또한, ‘
Collections.synchronizeMap
‘ 메소드를 사용하여 맵을 동기화된 맵으로 변환할 수 있습니다.
- 반면에 ‘
-
6. Null 허용 : 대부분의 ‘
Map
‘ 구현체는 키와 값으로 ‘null
‘ 을 허용합니다.(‘HashMap
‘, ‘LinkeHashMap
‘).- 하지만 ‘
Hashtable
‘ 은 ‘null
‘ 키나 값을 허용하지 않으며, ‘TreeMap
‘ 은 자연 정렬 또는 ‘Comparator
‘ 가 ‘null
‘ 을 처리할 수 있는 경우에만 ‘null
‘ 키를 허용합니다.
- 하지만 ‘
📝 정리.
이러한 특징들로 인해 ‘Map
‘ 은 다양한 애플리케이션에서 유연하고 효율적인 데이터 관리를 가능하게 합니다.
데이터를 쉽게 추가, 검색, 삭제할 수 있어 데이터 관리의 복잡성을 줄이고 성능을 최적화하는 데 기여합니다.
3. Generics.
자바 프로그래밍에서 제네릭스(Generics)는 클래스나 메소드에서 사용될 데이터 타입을 추상화하여 코드 작성 시점에는 구체적인 타입을 명시하지 않고, 객체 생성이나 메소드 호출 시점에 실제 사용할 타입을 지정할 수 있도록 하는 프로그래밍 기법입니다.
제네릭스(Generics)는 코드의 재사용성을 높이고, 타입 안정성을 강화하며, 캐스팅에 대한 오류 가능성을 줄이는 데 도움을 줍니다.
3.1 제네릭스(Generics)의 주요 특징.
-
1. 타입 안전성(Type Safety) : 제네릭스를 사용하면 컴파일 시점에 타입 체크가 가능하여, 실행 시점에서 발생할 수 있는
'ClassCastException'
과 같은 오류를 사전에 방지할 수 있습니다. -
2. 재사용성(Reusability) : 하나의 코드를 다양한 타입에 대해 재사용할 수 있습니다.
- 예를 들어, 제네릭 클래스나 메소드를 정의하면, 다양한 타입의 객체를 저장하거나 처리하는 로직을 단 한번만 작성하여 여러 타입에 걸쳐 사용할 수 있습니다.
- 3. 코드 간결성(Code Clarity) : 캐스팅을 줄여 코드가 더욱 간결하고 읽기 쉬워집니다.
3.2 제네릭스의 기본 문법.
-
클래스 선언 : 클래스 이름 뒤에
'<T>'
를 추가하여 제네릭 클래스를 선언합니다.- ‘T’ 는 타입 파라미터를 나타내며, 이는 클래스 내에서 사용될 데이터 타입을 대체하는 플레이스홀더 역할을 합니다.
public class Box<T> {
private T t; // T 타입의 객체를 위한 변수
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
-
메소드 선언 : 메소드 반환 타입 앞에 ’
<T>
‘ 를 추가하여 제네릭 메소드를 선언합니다.
public <T> T genericMethod(T t) {
return t;
}
-
제네릭 타입 제한(Bounded Type Parameters) : 특정 클래스의 하위 클래스만 타입 파라미터로 받도록 제한할 수 있습니다.
- 이는
'extends'
키워드를 사용하여 지정합니다.
- 이는
public class Box<T extends Number> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
📝 정리.
제네릭스(Generics)를 사용함으로써 개발자는 보다 타입-안전하고 유지보수가 용이한 코드를 작성할 수 있으며, 실행 시 타입 관련 문제를 효과적으로 줄일 수 있습니다.