Java

Java.API(Collection Framework) -generic , List , Set , Map

임혁진 2023. 11. 24. 16:40

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으로 반

 

맵을 반복하는 방법

Entry타입의<Integer,String>이 들어갔다

 

 

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());

 

 

 

}

}

키가 오름차순으로 정렬