Java.API(Collection Framework) -generic , List , Set , Map
Generic(제네릭)
- 제네릭이란 클래스나 인터페이스 선언에 유형 매개변수가 들어있는 클래스를 뜻합니다.
- 제네릭 타입은 클래스 또는 인터페이스 이름 뒤에 "<>"부호가 붙고, 그 사이에 파라미터가 위치합니다.
- 자바 5 버전부터 제네릭이 도입된 이후에는 제네릭 기능으로 인해 클래스에 원하지 않는 데이터형이 들어가는 것을 방지 할 수 있고, 반대로 값을 가져올 때도 형 변환을 하지 않게 되었습니다.
- 제네릭은 형 안정성(type safety)을 위해 사용합니다
public class Baisc {
public static void main(String[] args) {
//자바를 사용하다보면 ? 라고 하는 제네릭 문법이 보일 때가 있다.
//List<?> = 리스트 타입이라면 무엇이든 다 들어갈 수 있음
//List<? extends String> = ?가 String타입의 자식은 들어갈 수 있음
//List<? super Integer> = ?가 Integer의 형태가 될 수 있다면 들어갈 수 있음
List <Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list);
List<Integer> list2 = Arrays.asList(1,2);
System.out.println(list2);
System.out.println(list.containsAll(list2) ); //1,2가 포함되어있다면 true
System.out.println("-------------------------------------");
List<String> l1 = new ArrayList<>();
List<Integer> l2 = new ArrayList<>();
List<Object> l3 = new ArrayList<>();
// add1(l1);
// add1(l2);
// add1(l3);
//
// add2(l1);
// add2(l2); //x
// add2(l3); //x
//
// add3(l1); //x
// add3(l2);
// add3(l3);
}
public static void add1(List<?> list) {
}
public static void add2(List<? extends String> list) {
}
public static void add3(List<? super Integer> list) {
}
}
Generic이 없다면
public class ABC {
//무엇이든 저장할 수 있는 상자
private Object obj ;
public void setObj(Object obj) {
this.obj = obj;
}
public Object getObj() {
return obj;
}
}
public class Person {
}
public class MainClass {
public static void main(String[] args) {
ABC abc = new ABC();
abc.setObj("피카츄");
String name =(String)abc.getObj();
System.out.println(name);
//만약 사용할 때 잘못캐스팅 하면 예외가 발생.
//Integer age = (Integer)abc.getObj();
abc.setObj(new Person()); // Object obj = new Person();
Person p =(Person)abc.getObj();
abc.setObj(abc);
}
}
매번 형태나 , 형변환 등에 신경써야되고 그렇지 못하면 오류가 뜰 수 있다.
Generic 타입을 쓴다면
<> 안에서 저장되는 타입은 미정상태이다
- 대문자를 사용한다
-값을 꺼낼 때 형변환을 하지 않아도 된다.
public class ABC<T> {
//<타입>처럼 사용함
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
public class MainClass {
public static void main(String[] args) {
//ABC abc = new ABC(); // 제너릭 클래스 없이 하면 Object로 됨
//abc.setT("홍길동");
ABC<String> abc = new ABC<>(); //T에는 내가 저장하고 싶은 타입을
abc.setT("홍길동");
String name = abc.getT();
System.out.println(name);
System.out.println("----------------------------");
//int로 저장하는 용도의 객체 (반드시 wrapper만 쓸 수 있다)
ABC<Integer> abc2 = new ABC<>();
abc2.setT(1000000000);
int a = abc2.getT();
System.out.println(a);
System.out.println("----------------------------");
//Person 저장하는 용도의 객체 (뒤에 제너릭 생략이 가능)
ABC<Person> abc3 = new ABC<>();
abc3.setT(new Person());
Person p = abc3.getT();
System.out.println(p);
}
}
=> <> 사이에는 내가 저장하고 싶은 타입 넣기
=> 객체 생성시 뒤의 제너릭은 생략이 가능
Generic multi
public class ABC<A,B> {
//멀티제너릭 (A,B를 타입으로 사용)
private A key;
private B value;
public void setData(A key , B value) {
this.key = key;
this.value = value;
}
public B getValue(A key){
return value;
}
}
public class Main {
public static void main(String[] args) {
ABC<Integer, String> abc = new ABC<>();
abc.setData(1, "홍길동");
System.out.println(abc.getValue(1));
}
}
Collection APi
1.List 계열
ArrayList , LinkedList,
1) ArrayList
=>배열기반의 리스트
=>가장 평범하게 많이 사용한다.
=>인덱스(순서o),값의중복(o), 동적으로 크기 조정
ArrayList의 유용한 메소드
ArrayList<String> list = new ArrayList<>();
List<String> list1 = new ArrayList<>();
list.add("Java"); - 값의 추가
list.size(); - 크기 확인
list.add(2, "이순신"); -//값을 중간에 추가
//값을 한번에 추가
String[] arr = {"A","B","C"};
List<String> newList = Arrays.asList(arr);
list.addAll(newList); -
//값의 확인 get
String x = list.get(0); // list[0] == list.get[0];
//값의 삭제 remove(인덱스),remove(값)
list.remove(2);
list.remove("A");
list.set(3, "홍길동"); - //값의 수정 set
list.contains("Java") - //포함여부 확인 - boolean 타입
list.clear();- //전체삭제
public class ArrayListEx01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
List<String> list1 = new ArrayList<>();
//값의 추가
list.add("Java");
list.add("Spring");
list.add("Database");
list.add("JS");
list.add("Docker");
//크기
list.size();
//값을 중간에 추가
list.add(2, "이순신");
//값을 한번에 추가
String[] arr = {"A","B","C"};
List<String> newList = Arrays.asList(arr);
list.addAll(newList);
//값의 확인 get
String x = list.get(0); // list[0] == list.get[0];
//값의 삭제 remove(인덱스),remove(값)
list.remove(2);
list.remove("A");
//값의 수정 set
list.set(3, "홍길동");
//포함여부 확인
if(list.contains("Java")) {
System.out.println("Java가 존재함");
}
//전체삭제 clear
list.clear();
}
}
3)LinkedList
=>노드(객체) 기반의 리스트(연결리스트)
=>노드(객체) 주소값으로 참조해서 연결해놓은 구조
=>ArrayList과 사용방법은 동일함
=>ArrayList보다 삽입,삭제는 빠름 , 조회는 느림
=>Queue를 구현하고 있기 때문에, 큐처럼도 사용이 된다 (큐에 담으면 큐 처럼 리스트에 담으면 리스트처럼)
LinkedList의 유용한 메소드
//ArrayList와 사용방법 동일함
LinkedList<String> list = new LinkedList<>();
//값의 추가
list.add("홍길동");
list.add("이순신");
list.add("홍길자");
//LinkedList만의 기능 ,앞의추가,끝의추가
list.addFirst("A");
list.addLast("B");
//값 얻기 get(idx)
String x =list.get(0);
//값 삭제 remove(idx)
list.remove(0);
list.remove("홍길동");
//값의 수정
list.set(1, "홍길순");
----------Que의 기능-----------
//뒤에 추가
list.offer("1");
list.offer("2");
//앞에 삭제
System.out.println(list.poll());
//값만 확인하기 peek
list.peek();
public class LinkedListEx01 {
public static void main(String[] args) {
//ArrayList와 사용방법 동일함
LinkedList<String> list = new LinkedList<>();
//List<String> list = new LinkedList<>(); //순수하게 리스트 기능만 사용가능
//Queue<String> list = new LinkedList<>();//Que 처럼 사용됨
//값의 추가
list.add("홍길동");
list.add("이순신");
list.add("홍길자");
System.out.println(list.toString());
//LinkedList만의 기능 ,앞의추가,끝의추가
list.addFirst("A");
list.addLast("B");
System.out.println(list.toString());
//값 얻기 get(idx)
String x =list.get(0);
System.out.println(x);
//값 삭제 remove(idx)
list.remove(0);
list.remove("홍길동");
System.out.println(list.toString());
//값의 수정
list.set(1, "홍길순");
System.out.println(list.toString());
System.out.println("---------Que의 기능------");
//뒤에 추가
list.offer("1");
list.offer("2");
System.out.println(list.toString());
//앞에 삭제
System.out.println(list.poll());
System.out.println(list.toString());
//값만 확인하기 peek
list.peek();
System.out.println(list.peek());
}
}
2) Stack
=> Last in First out (LIFO)
=> 나중에 들어간건 먼저 나온다
Stack 의 유용한 메소드
=> push() 데이터삽입
=> pop()데이터 삭제
public class StackEx01 {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
// Vector<String> stack = new Stack<>();
// List<String> list =new Stack<>();
stack.push("홍길동");
stack.push("이순신");
stack.push("홍길자");
//컬렉션의 값을 문자열 형태로 출력
System.out.println(stack.toString());
//컬렉션의 사이즈기능
System.out.println(stack.size());
//컬렉션이 비어있는지 확인하는 기능
System.out.println(stack.isEmpty());
//삭제와 동시에 반환
String v1 = stack.pop();
String v2 = stack.pop();
String v3 = stack.pop();
System.out.println(v1);
System.out.println(v2);
System.out.println(v3);
System.out.println(stack.toString());
System.out.println(stack.isEmpty());
}
}
2. Queue계열
priorityQueue, Dequeue
1)priorityQueue
=> First in First Out (FIFO)
=> 먼저 들어간 건 먼저 나온다
=> 스케쥴링 작업에 사용됨
=>자바에서는 Queue인터페이스를 구현한 priorityQueue, Dequeue 등이 있다.
=>priorityQueue 우선순위 큐 , 삽입한 값을 자동으로 정렬해서 가지고 있는다.
=>문자열 비교 or 객체 비교를 하기 위해선 비교하는 메소드를 제공해야 된다.
=> (implements Comparable<>)
Queue 의 유용한 메소드
=> offer(int a) 데이터 삽입 ,
=> polll() 데이터 꺼내기
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//비교의 우선순위를 주기위한 메서드 // Comparable 인터페이스 구현
@Override
public int compareTo(Person o) {
//문자비교
//return name.compareTo( o.getName() ) ;
//return o.getName().compareTo(name); - 반대
//return Integer.compare(age, o.getAge());
return Integer.compare(o.getAge(), age);
}
//오버라이딩 toString - 객체의 멤버변수를 빠르게 확인
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class PriorityQueueEx {
public static void main(String[] args) {
//우선순위큐 - 자동 정렬됨
PriorityQueue<Integer> que = new PriorityQueue<>();
que.offer(3);
que.offer(4);
que.offer(3);
que.offer(1);
que.offer(2);
System.out.println(que.toString());
//데이터꺼내기
System.out.println( que.poll() ); //1
System.out.println( que.poll() ); //2
System.out.println( que.poll() ); //3
System.out.println( que.poll() ); //3
System.out.println( que.poll() ); //4
System.out.println("-----------------------------------------");
//객체를 Que에 넣는 작업
//객체를 Que에 넣을 때는 우선순위를 지정하는 방법이 정의되어야 합니다.
PriorityQueue<Person> q = new PriorityQueue<>();
//a > 0 뒤에가 우선순위, a < 0 앞에가 우선순위, a == 0 같음
System.out.println("홍길동".compareTo("홍길자") ); //-5047 홍길동이 홍길자보다 우선순위
q.offer( new Person("홍길동", 20) );
q.offer( new Person("홍길자", 30) );
q.offer( new Person("이순신", 40) );
q.offer( new Person("피카츄", 50) );
//나이를 기준으로 우선순위 지정 했다.
System.out.println( q.poll() ); //피카츄
System.out.println( q.poll() );//이순신
System.out.println( q.poll() );//홍길자
System.out.println( q.poll() );//홍길동
Person p = new Person("sdf", 1);
}
}
2)Deque
=> 양방향 큐(양측에서 삽입과 삭제가 가능한 구조)
=> ArrayDeque라는 클래스를 사용해서 구현됨
=>Deque인터페이스를 상속받습니다.
public class DequeEx {
public static void main(String[] args) {
//양쪽방향에서 삽입삭제 가능한 Que
//ArrayDeque<Integer> que = new ArrayDeque<>();
Deque<Integer> que = new ArrayDeque<>();
que.offerLast(3);
que.offerLast(4);
que.offerLast(1);
que.offerLast(2);
System.out.println( que.toString());
System.out.println( que.pollFirst() );
System.out.println( que.pollFirst() );
System.out.println( que.pollFirst() );
System.out.println( que.pollFirst() );
System.out.println( que.toString() );
System.out.println("-----------------------------------------");
//앞에서 삽입
que.offerFirst(1);
que.offerFirst(2);
que.offerFirst(3);
que.offerFirst(4);
System.out.println(que.toString());
//뒤에서 삭제
System.out.println(que.pollLast() );
System.out.println(que.pollLast() );
System.out.println(que.pollLast() );
System.out.println(que.pollLast() );
System.out.println("--------------------------------------");
//peek - 값을 확인 (삭제 x )
que.offer(1);
que.offer(2);
que.offer(3);
System.out.println(que.toString() );
System.out.println(que.peek() );
System.out.println(que.toString() ); //큐는 변함 없음
System.out.println(que.peekLast() );
System.out.println(que.toString() ); //큐는 변함 없음
System.out.println(que.peek() );
}
}
Deque의 유용한 메소드
offerfirst == 앞에서 뒤로 넣기
offerlast == offer();
poolfirst == 젤 앞의 것 빼기 == poll();
poollast == 젤 뒤에 것 빼기
3.set 계열
=> 데이터를 중복 없이 저장하는 자료구조(중복x)
=> Hash알고리즘을 사용해서 저장 순서를 알 수 없다(인덱스x , 순서x)
=> 저장 순서를 알수가 없기 때문에 , 하나의 데이터를 조회하는 메소드가 없다.
=> 값의 확인은 반복자(iterator)를 사용해서 확인함.
=>HashSet , TreeSet , LinkedHashSet
=> HashSet - 기본이 되는 set을 구현한 클래스
=> TreeSet - 오름차순 정렬이 된 set계열 클래스
=> LinkedHashSet - 순서도 가지고 있는 set계열 클래스
**반복자(iterator)의 주요 메소드
=> hasnext() : 가져올 객체가 있으면 true , 없으면 false를 리턴
=> next() ; 컬렉션에서 하나의 객체를 가져옴.
=>remove(): set 컬렉션에서 객체를 제거함.
1) HashSet
//set객체 생성
Set<String> set = new HashSet<>();
//값의 추가 add
set.add("java");
set.add("java"); //중복 x
set.add("js");
set.add("python");
set.add("spring");
//값이 포함되어 있는지 확인
if(set.contains("java")) {
System.out.println("java가 포함됨");
}
//값을 얻을 때는 반복자(iterator)개념을 사용해서 반복해야 함
Iterator<String> iter = set.iterator();
while(iter.hasNext()) { //다음 값이 있다면 true
System.out.print(iter.next()+ " "); // 토큰처럼 하나씩 뽑아냄 토큰도 반복자
}
for(String s : set) {
System.out.println(s);
}
//값의 삭제
set.remove("js");
System.out.println(set.toString());
public class HashSetEx01 {
public static void main(String[] args) {
//set객체 생성
Set<String> set = new HashSet<>();
//값의 추가 add
set.add("java");
set.add("java"); //중복 x
set.add("js");
set.add("python");
set.add("spring");
System.out.println(set.size() );
System.out.println(set.toString() ); //순서 x
//값이 포함되어 있는지 확인
if(set.contains("java") ) {
System.out.println("java가 포함됨");
}
//값을 얻을 때는 반복자(iterator) 개념을 사용해서 반복해야 합니다.
Iterator<String> iter = set.iterator();
while(iter.hasNext()) { //다음이 있다면 true
System.out.println(iter.next());
}
System.out.println("----------------------------");
for(String s : set ) {
System.out.println(s);
}
//값의 삭제
set.remove("js");
System.out.println(set.toString());
}
}
2) TreeSet
=>정렬 된 set ->사전순으로 정렬됨
=>사용방법은 HashSet과 동일함
public class TreeSetEx01 {
public static void main(String[] args) {
//TreeSet = 정렬 된 셋
//사용방법은 Hashset과 동일함
Set<String> set = new TreeSet<>();
set.add("홍길동");
set.add("홍길자");
set.add("짱구");
set.add("철수");
set.add("훈이");
set.add("유리");
System.out.println(set.toString());
//나머지 기능은 HashSet과 동일함
}
}
4. Map 계열 (key , value)
=> Map 컬렉션은 키 (key)와 값(value)으로 구성된 Entry객체를 저장하는 구조를 가지고 있다.
=> 객체 생성시 멀티제너릭을 이용해서 key에 대한 타입,value에 대한 타입을 지정
=> 키는 중복저장x 될 수 없지만 값은 중복저장 될 수 있다.
=>key를 알고 있다면, 값을 빠르게 찾아내는 특징을 가진다 (탐색이 가장빠름)
=>프로그램에서 많이 사용된다
=>HashMap - 키가 HashSet으로 저장되는 형태
=>TreeMap - 키가 TreeSet으로 저장되는 형태
=>LinkedHashMap - 키가 LinkedHashSet으로 저장되는 형태
HashMap
public class HashMapEx01 {
public static void main(String[] args) {
//<키에대한타입, 값에대한타입>
//HashMap<Integer, String> map = new HashMap<>();
Map<Integer, String> map = new HashMap<>();
//값을 추가 put
//키값은 고유해야 합니다.
map.put(1, "짱구");
map.put(2, "유리");
map.put(3, "훈이");
map.put(4, "철수");
map.put(5, "짱구");
map.put(6, "맹구");
System.out.println(map.size());
System.out.println(map.toString() );
//값의 수정 - 맵에 동일한 키를 이용해서 변경하면 됩니다.
map.put(5, "홍길동");
System.out.println(map.toString());
//값을 얻기 get
String value = map.get(3); //키
System.out.println("3번 키에대한 값:" + value);
//값을 삭제 remove
map.remove(5); //키
System.out.println(map.toString());
//키 or 값의 포함여부
System.out.println( map.containsKey(3) ); //키가 있다면 true
System.out.println( map.containsValue("짱구") ); //값이 있다면 true
//맵을 반복하는 방법
Set<Integer> set = map.keySet(); //키를 set으로 뽑아서 반환
for(Integer i : set) {
System.out.println("키:" + i + ", 값:" + map.get(i) );
}
System.out.println("-----------------------------------");
Set<Entry<Integer, String>> entry = map.entrySet();
for(Entry<Integer, String> e : entry ) {
//엔트리는 key, value에 대한 getter를 제공합니다.
System.out.println("키:" + e.getKey() + ", 값:" + e.getValue() );
}
System.out.println("--------------------------------------------------");
}
}
Map의 유용한 메소드
put( , ) , get( ) 가 가장 중요
put( ) - 값을 집어넣기
get(key) - 키에대한 값을 리턴하기
remove(key) - 키의 삭제
containsKey(key) - key의 값이 포함되어있는지
containsValue(value) - value 가 포함되어있는지
keySet() - >key를 set으로 반환
EntrySet() - >Entry를 set으로 반
맵을 반복하는 방법
TreeMap
public class TreeMapEx01 {
public static void main(String[] args) {
//TreeMap은 사용방법이 동일합니다.
//키가 저장되는 구조가 이진탐색트리 를 이용해서 키를 저장합니다.
//키가 오름차순정렬이 됩니다.
TreeMap<String, Object> map = new TreeMap<>();
map.put("짱구", "20세");
map.put("유리", "30세");
map.put("훈이", "30세");
map.put("맹구", "20세");
System.out.println(map.toString());
Object o = map.get("맹구");
System.out.println( (String)o );
//검색에 특화된 기능을 제공해줍니다.
Entry<String, Object> entry = map.higherEntry("유라"); //유라
//트리구조에서 한단계 더 높은 위치에 있는 키중에서 가장 작은값
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
}