Code.presso Java 웹 개발 트랙 체험단 활동 2주차 두번째 코스로, 지난 시간에 이어 패키지와 컬렉션 프레임워크인 List에 대해 학습한 내용을 정리해보려고 한다!
강의 제목은 "Java Programming 초급" 으로, 자세한 정보는 👇🏻아래👇🏻 링크를 통해 확인할 수 있다.
✋🏻 포스팅 내 사용된 사진 파일들의 저작권은 모두 코드프레소에 있으며, 강의자료 공유 및 업로드는 불가능합니다.
패키지란 관련있는 클래스를 한 데 묶어 놓은 그룹을 의미한다.
패키지는 클래스를 구분하는 일종의 디렉토리로 하위 계층 구조를 가질 수 있다.
패키지명은 소문자로만 작성하고 클래스들의 묶음을 표현하는 의미 있는 이름으로 작성해야 한다.
패키지는 계층 구조를 가지며 일반적으로 1차도메인.회사명
으로 시작된다.
com.회사명.프로젝트명.모듈명.서브모듈명
org.회사명(-조직명).프로젝트명.모듈명.서브모듈명
com.codepresso.newtube.user
또한 패키지를 생성하면 실제 디렉토리도 실제 생성되는데, 이때 패키지의 이름과 구조는 실제 OS의 디렉토리 구조와 매핑된다.
패키지명은 사진과 같이 계층 구조의 전체 이름을 모두 포함하고 하위 계층 구조는 점(.
)을 통해 구분할 수 있다.
📌 FQCN (Fully Qualified Class Name)
클래스의 FQCN은 패키지 명을 모두 포함한다
➡️패키지명 + 클래스명
모든 클래스는 반드시 하나 이상의 패키지에 속한다.
클래스 생성시 패기지를 선언하지 않으면, 이름 없는 패키지(Unnamed Package)에 포함되고,
패키지를 선언하지 않은 모든 클래스들은 모두 동일한 패키지에 속한다.
패키지를 선언한다는 것은 해당 클래스가 어떤 패키지에 있다고 명시하는 것이다.
package
키워드를 통해 패키지명을 선언할 수 있고, 이 선언문은 .java
파일의 가장 첫번째 라인에 작성한다.
모든 클래스에 단 한번만 패키지를 선언할 수 있다.
Intellj
에서 위와 같은 방법으로 패키지를 생성할 수 있다.
패키지를 생성한 후 패키지 안에 User
라는 클래스를 생성해보자.
클래스를 생성하게 되면 클래스 파일에 위와 같이 자동으로 선언문이 생긴 것을 확인할 수 있다.
다른 패키지에 속한 클래스를 사용할 때에는 클래스의 FQCN을 사용해야 한다.
FQCN의 반복을 피하기 위해 import
문을 선언한다.
UserManager
클래스에서 User
클래스를 사용하기 위해서는 UserManager
소스코드 상단에 import
문을 이용하여 선언문을 추가해야 한다.
만약 특정 패키지 내의 모든 클래스 사용하는 경우에는 FQCN 대신 패키지명.*
으로 특정 패키지 내의 모든 클래스를 사용 가능하다.
접근 제어자를 명시하지 않으면, default 접근 제어자가 자동으로 적용된다.
같은 패키지 내에서는 접근 가능하지만, 다른 패키지에서는 접근이 불가능하다.
패키지에서만 사용 가능하게 하고 다른 패키지에서는 접근을 못하게 하고 싶다면, public으로 두지 말고 default를 사용하는 것이 좋다.
protected 접근 제어자는 같은 패키지 간에는 접근이 가능하다.
또한 상속 관계에서, 부모 클래스의 패키지가 달라도 자식 클래스에서 부모 클래스의 멤버에 접근이 가능하다는 특징이 있다.
protected 접근 제어자는 모든 자식 클래스에서의 접근을 가능하게 한다.
외부 패키지에 있는 자식 클래스라도 접근이 가능하다.
사진을 봤을 때, 다른 패키지에 존재하지만 User
클래스를 상속하고 있는 PaidUser
클래스에서는 접근이 가능하다.
그러나 패키지가 다르면서 상속관계도 아닌 UserManager
에서는 접근이 불가능하다!
여러 건의 데이터를 다루기 위해서는 Array
와 같은 데이터를 다루기 위한 자료구조의 구현체가 필요하다.
컬렉션 프레임워크란, 다양한 자료구조의 구현을 위한 클래스와 인터페이스의 집합이다.
자바의 컬렉션 프레임워크에서는 각각의 특성에 알맞은 클래스 라이브러리를 제공하고 있다!
java.util.ArrayList<E>
java.util.HashSet<E>
java.util.HashMap<K,V>
이 세가지 각각에 대해서는 바로 다음 강의부터 자세히 학습할 수 있다!
Array
는 데이터 개수의 변경이 불가능했지만, ArrayList
는 데이터 개수의 동적인 변경이 가능하다.
또한 Array
의 데이터 타입은 객체는 물론 Primitive type 값을 가질 수가 있었지만, ArrayList
는 객체만을 원소로 가진다.
컬렉션 프레임워크에는 다양한 자료구조를 제공하기 위해서 위와 같은 총 3개의 주요 인터페이스를 제공한다.
List
Set
인터페이스가 한 그룹, Map
인터페이스를 한 그룹으로 나누는데 그 이유는 상속받는 인터페이스가 다르기 때문이다!
java.util.Collection<E>
인터페이스 그룹
List
Set
인터페이스는 모두 Collection
인터페이스를 상속받는다.java.util.Map<K,V>
인터페이스 그룹
Map
인터페이스는 구조상의 차이로 Collection
인터페이스를 상속받지 않고 독립적으로 정의되어 있다.java.util.List<E>
인터페이스java.util
이라는 패키지에 구현체가 존재하게 된다.
List
인터페이스를 구현한 ArrayList
LinkedList
Stack
클래스들 또한 동일한 특징을 가진다. java.util.Set<E>
인터페이스java.util
이라는 패키지에 구현체가 존재하게 된다.
Set
인터페이스를 구현한 HashSet
TreeSet
클래스들 또한 동일한 특징을 가진다. java.util.Map<K,V>
인터페이스java.util
이라는 패키지에 구현체가 존재하게 된다.
Key
와 Value
로 이루어진 pair를 가지는 데이터의 집합이다.Key
는 중복을 허용하지 않고, Value
는 중복을 허용한다.Map
인터페이스를 구현한 HashMap
TreeMap
클래스들 또한 동일한 특징을 가진다. 제네릭(Generic) 이란 데이터의 타입을 일반화(Generalize)한다는 의미이다.
클래스나 메소드에서 사용할 데이터의 타입을 컴파일 시 type check 하여 런타임 시의 안정성이 보장된다.
1. 제네릭을 사용한 클래스 정의 문법
➡️ class [ClassName]<T>
<T>
: 클래스 내부에서 사용될 임의의 데이터 타입을 T
라는 타입 변수로 지정한다.T
를 이용해 클래스 내부 변수 생성 및 메소드 인자, 반환 값의 타입 지정이 가능하다.T
는 임의 값으로 지정이 가능하다.2. 제네릭을 사용한 클래스 객체 생성 문법
➡️ [ClassName]<[Type-Class]> [object-name] = new [ClassName]<>();
ClassName
: 생성하고자 하는 클래스 지정Type-Class
int
➡️Integer
, float
➡️Float
, double
➡️Double
...)가장 큰 장점은 바로 클래스 내 임의의 변수를 매번 다른 데이터 타입으로 지정하여 객체 생성이 가능하다는 것이다.
int
로도 쓰고, String
으로도 쓰는 범용성을 제네릭으로부터 얻어낼 수 있다.
📌
Object
는 최상위 클래스이므로 제네릭과 같은 범용성 확보가 가능하다.
그러나 이 경우, 컴파일 시 타입 체크가 되지 않는다!
List
자료 구조 데이터로 매분 마다 수집 된 하루치 주식 가격 데이터를 예로 들 수 있다.
이는 여러 건의 데이터를 하나로 묶어서 관리한다는 특징이 있다.
또한 이 데이터들은 순서가 존재하고, 중복되는 데이터가 존재할 수 있다!
List<E>
인터페이스에 대한 이해이제부터 List<E>
인터페이스에 대한 이해를 조금 더 높여보자😃❗️
List<E>
인터페이스는 Collection<E>
인터페이스를 상속하여 정의된 인터페이스이다.
그렇다보니, 위와 같이 Collection<E>
인터페이스에서 정의된 메소드에 List
자료구조에 필요한 메소드가 추가로 정의되어 있다!
대표적인 List
자료구조의 컬렉션 클래스로는 ArrayList<E>
가 있다.
💡 ArrayList<E>
클래스 특징
Array
와 가장 유사한 컬렉션 클래스이다.Array
처럼 객체 내부 데이터에 접근하기 위한 인덱스가 존재한다.Array
와 다르게 생성된 객체에서 데이터의 추가과 삭제가 자유롭게 가능하다.java.util
패키지에 존재한다.ArrayList<E>
객체의 생성과 데이터 추가ArrayList<E>
객체 생성객체 생성 문법은, 앞서 배웠던 제네릭한 type variable을 포함하는 클래스 객체를 생성하는 방법과 동일하다.
ArrayList
클래스는 java.util
패키지에 존재하기 때문에, 이를 가져오기 위해서는 클래스가 존재하는 전체 path 정보를 넣어주어야 한다.
➡️ import java.util.ArrayList
ArrayList<E>
객체의 데이터 추가boolean add(E e)
boolean
타입의 값을 반환한다.📌
Class
객체를 데이터로 추가할 수도 있다
void add(int index, E e)
boolean addAll(Collection<? extends E> C)
Collection
객체의 데이터들을 모두 추가한다.ArrayList
객체 생성 시 정의한 데이터 타입을 원소로 가지는 Collection
객체여야 한다.boolean addAll(int index, Collection<? extends E> C)
Collection
객체의 데이터들을 추가한다.ArrayList<E>
객체의 데이터 탐색과 변경ArrayList<E>
객체의 데이터 탐색E get(int index)
int indexOf(Object o)
-1
을 반환한다.boolean contains(Object o)
boolean
타입으로 결과를 반환한다.int size()
ArrayList<E>
객체의 데이터 변경void clear()
[ArrayList 객체 이름].clear()
E remove(int index)
boolean remove(Object o)
boolean
타입으로 반환한다.boolean removeAll(Collection<?> c)
Collection
객체가 가지고 있는 데이터들을 모두 제거한다.E set(int index, E e)
ArrayList<E>
객체의 데이터 정렬ArrayList<E>
객체의 데이터 정렬void java.util.Collections.sort(List<T> list)
java.util.Collections
클래스의 static sort
메소드를 사용해 데이터를 오름차순으로 정렬한다.List<T>
인터페이스 구현 클래스의 객체를 전달한다.void java.util.Collections.reverse(List<T> list)
java.util.Collections
클래스의 static sort
메소드를 사용해 데이터를 내림차순으로 정렬한다.List<T>
인터페이스 구현 클래스의 객체를 전달한다.현재까지는 ArrayList
객체를 생성할 때 비어있는 ArrayList
를 생성하고 add()
와 같은 메소드를 통해 데이터를 넣어주었다.
그러나 실제 프로그래밍을 할 때는 Array
객체를 이용하는 경우가 더 많다!
java.util.Arrays
클래스의 static asList()
메소드를 사용하여 객체를 간단히 생성할 수 있는데, 여기서 주의할 점은 이 클래스가 jav.util.ArrayList
클래스와는 다르다는 것이다!
사진과 같이 ArrayList
를 만들기 위해 필요한 데이터들을 data
라는 배열으로 만들어주고, 이를 Arrays
라는 클래스에 존재하는 asList()
메소드의 인자로 넣어준다.
코드프레소 홈페이지(https://www.codepresso.kr/)에는 오늘 포스팅한 패키지와 List 관련 강의뿐만 아니라 다양한 강의들이 개설되어 있으니 모두 한번 씩 살펴보고 수강해보면 좋을 것 같다😃