▸JAVA/기본 문법

컬렉션 프레임워크(컬렉션 API)_배열 다루기 [4/4]

코데방 2019. 12. 11.
728x90

컬렉션 프레임워크에서 배열을 다루다보니 개념정리가 잘 되어있지 않은 상태에서는 꽤 혼란스럴 수 있습니다. 클래스가 많은데 이리저리 연관되어 있는 경우가 많아서 그런 듯 합니다.

 


 

컬렉션 프레임워크의 전체 구성도는 아래와 같습니다. 실제로는 추상 클래스까지 중간에 있어서 조금 더 복잡한 구조이지만 간략히 필요한 것만 그렸습니다.

 

 


 

[ 완전한 List 계열 컬렉션 만드는 법 ]

먼저 List 계열의 클래스들(ArraysList, Vector, LinkedList 등)은 List 인터페이스를 상속받았기 때문에 오버라이딩이 가능합니다. 즉, List 타입에 담아줄 수 있습니다. 굳이 List 계열의 컬렉션 타입을 List 타입에 담아주는 이유는 컬렉션을 여러 효율적인 알고리즘으로 처리 해주는 Collections 클래스의 메소드들이 매개변수를 List 타입으로 하고 있기 때문입니다. List 계열의 컬렉션들은 어차피 하나의 배열이라고 봐도 무방합니다. 이 배열들은 List 인터페이스에서 상속받은 항목을 기초로 하고 있기 때문에 공통적인 속성을 띄고 있습니다. 따라서 Collections 클래스에서는 오버라이딩 된 List 타입으로 매개변수를 받아서 배열을 처리하는 것이죠.

 

따라서 각 클래스의 고유한 메소드를 사용하려면 해당 클래스의 인스턴스를 생성해야 하지만, Collections 클래스를 사용해서 컬렉션을 다루거나, List 인터페이스에 정의된 공통 메소드만 필요한 경우라면 List 타입으로 인스턴스를 생성하면 됩니다. 보통은 List 타입으로 생성해서 사용하는 경우가 많습니다. 당연한 말이지만 이 경우 List 클래스도 import 해줘야 합니다.

※ Point
본래 8개의 원시타입 변수는 컬렉션의 배열 요소로 사용할 수 없습니다. 하지만 사용이 가능한 것처럼 보이는 이유는, 제네릭에 원시타입을 넣어 컬렉션 생성 시 자동으로 원시타입을 래퍼 클래스로 박싱해주기 때문입니다. 오토박싱이 이루어진다는 의미이죠. 그래서 int 타입의 경우 List<Integer>와 같이 제네렉을 래퍼 클래스명으로 지정해줘야 합니다.
package study.first;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

public class Main  {

	public static void main(String[] args) {
		
		List<String> arr1 = new ArrayList<String>();
		List<String> arr2 = new Vector<String>();
		List<String> arr3 = new LinkedList<String>();		
	}
}

 


 

[ Arrays 클래스의 asList() 메소드를 이용해 List 타입 컬렉션을 만드는 법 ]

또한 배열을 다루는 Arrays 클래스의 메소드를 이용해 List 타입의 배열을 생성할 수도 있습니다. 하지만 이 경우는 위와 같이 완전한 형태의 List 컬렉션을 만드는 것이 아니라 개념을 바로 알고 사용해야 합니다. 

 

Arrays.asList()는 일반 배열을 List 타입의 인스턴스에 담아주는 메소드입니다. 주의할 점은 "값의 복사가 아닌 배열 주소의 전달"이라는 점입니다. 배열을 컬렉션처럼 다루기 위해 List타입으로 변환해주지만 실제로는 일반 배열의 주소를 가지고 있는 List 인스턴스가 되는 것입니다. 즉, 인스턴스에서 메소드를 통해 값을 변경하면 원본 배열의 값도 같이 변경됩니다. 

 

그리고 일반 배열은 컬렉션처럼 배열 사이즈가 자동으로 변환되지 않기 때문에 List의 요소 추가, 삭제 메소드를 사용할 수 없습니다. 즉, 배열의 크기 자체를 변경하는 행위 빼고 다른 메소드들은 적용이 가능합니다. 일반 배열의 성질을 가진 List 컬렉션이라고 생각하면 됩니다.

package study.first;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;


public class Main  {

	public static void main(String[] args) {
		
		// 배열 및 List 타입 인스턴스 생성
		Integer[] list = {1,2,3,4,5};
		List<Integer> arr = Arrays.asList(list);
		
		// 정상적으로 데이터가 삽입되었음
		System.out.println(arr);  // [1, 2, 3, 4, 5]
		
		// 값 변경은 정상적으로 되지만 원본 배열값도 같이 바뀜
		arr.set(0, 111);
		System.out.println(arr);  // [111, 2, 3, 4, 5]
		System.out.println(Arrays.toString(list)); // [111, 2, 3, 4, 5]
		
		// 기타 메소드 사용 가능 (배열 크기가 변경되지 않는 메소드)
		System.out.println(arr.contains(5)); // true
		System.out.println(arr.indexOf(4));  // 3
		
		Collections.sort(arr);
		System.out.println(arr);  // [2, 3, 4, 5, 111]
		
//		에러 발생 (추가 삭제 불가)
//		arr.remove(0);
//		arr.add(10);
//		System.out.println(arr);
	}	
}

 

 

아래와 같이 Arrays.asList() 메소드를 통해 초기값을 한번에 넣어주는 방법도 사용할 수 있습니다. 이 경우에는 완전한 컬렉션 타입으로 생성됩니다.

package study.first;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {

	public static void main(String[] args) {

		// 배열 및 List 타입 인스턴스 생성
		Integer[] list = { 1, 2, 3, 4, 5 };
		List<Integer> arr = new ArrayList<>(Arrays.asList(list));

		System.out.println(arr); // [1, 2, 3, 4, 5]

		// 값 변경 시 (원본이 바뀌지 않음)
		arr.set(0, 111);
		System.out.println(arr); // [111, 2, 3, 4, 5]
		System.out.println(Arrays.toString(list)); // [1, 2, 3, 4, 5]

		// 데이터 추가/삭제 가능한 컬렉션 타입으로 생성되었음
		arr.add(1234);
		System.out.println(arr); // [111, 2, 3, 4, 5, 1234]
	}
}

 

Collections Class를 이용해서 컬렉션을 다루는 메소드는 아래 링크를 참조하시면 됩니다.

2019/12/12 - [JAVA/라이브러리(API)] - java.util.Collections 클래스의 주요 메소드 [1/1]

 


 

또한 객체(인스턴스)의 배열을 생성해서 사용할 때도, C언어의 구조체 배열과 동일하게 생각하면 됩니다. 다만 배열처럼 arr[i] 형태가 아닌 arr.get(i) 형태로 메소드를 사용한다는 점만 다릅니다. C만 하다가 Java에 넘어와서 가장 헷갈렸던 사용법 중 하나가 배열이었던 것 같습니다. 캡슐화로 인해 구조체(클래스 인스턴스)의 변수(필드)에 직접 접속을 못하니 개념이 많이 헷갈리더라구요. 아래와 같이 사용한다는 점만 알면 금방 익숙해 질 것 같습니다. 

 

package study.first;

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

public class Main  {

	public static void main(String[] args) {
		
		List<Obj> arr = new ArrayList<Obj>();
	
		// Obj 생성해서 리스트에 추가
		arr.add(createObj(1, "apple"));
		arr.add(createObj(2, "banana"));
		arr.add(createObj(3, "Orange"));
		
		// 순회 출력
		for (int i = 0; i < arr.size(); i++)
			System.out.println(arr.get(i).a + " : " + arr.get(i).b);		
	}
	
	
	// Obj 인스턴스 만들어서 값넣고 반환
	static Obj createObj(int a, String b) {
		
		Obj temp = new Obj();
		temp.a = a;
		temp.b = b;
		
		return temp;		
	}	
}

// Obj 클래스
class Obj {	
	
	public int a;
	public String b;	
}

 

728x90

댓글

💲 추천 글