100일 챌린지/빅데이터기반 인공지능 융합 서비스 개발자

Day 11 - generic, 순서가 없는 자료구조(Enumeration),그리고 Map

ksyke 2024. 8. 5. 10:55

Generic

  • JDK 1.5 버전부터 나온 문법
  • 문법적으로 자료형을 제약, 개념적으로 확장한다.
  • 캐스팅이 필요하지 않아 캐스팅 미스매치로 일어나는 Exception오류를 피할 수 있다.
// 캐스팅이 필요한 리스트
ArrayList list1 = new ArrayList();
list1.add("문자열");
System.out.println(list1.get(0));
String msg1 = (String) list1.get(0);
System.out.println(msg1);

// 캐스팅이 필요하지 않은 general 리스트 
ArrayList<String> list2 = new ArrayList<String>();
list2.add("문자열");
System.out.println(list2.get(0));
String msg2 = list2.get(0);
System.out.println(msg2);

generic을 이용한 클래스와 상속 (개념적 확장) - class 에서의 generic

interface Pen{
    void draw();
}

class Ballpen1 implements Pen{
    String bold = "진한";
    public void draw() {
        System.out.println(bold + " 선을 긋습니다. ");
    }
}

class Pencil implements Pen{
    String bold = "희미한";
    public void draw() {
        System.out.println(bold + " 선을 긋습니다. ");
    }
}

class Ball implements Pen{
//    String bold = "희미한";
    public void draw() {
        System.out.println("공놀이한다.");
    }
}

class Box1<T>{ // 클래스를 만들 단시 generic을 설정한다. 
    T pen;
    public void setPen(T pen) {
        this.pen = pen;
    }
    public T getPen() {
        return this.pen;
    }
}

public class Ex02_1 {

    public static void main(String[] args) {

        Box<Pencil> box = new Box<Pencil>();

        box.setPen(new Pencil());

        Pencil1 pen1 = box.getPen();
        pen1.draw();

        Box1<Ballpen> box2 = new Box<Ballpen>();

        box2.setPen(new Ballpen());

        Ballpen pen2 = box2.getPen();
        pen2.draw();

        Box1<Ball> box3 = new Box1<Ball>();

        box3.setPen(new Ball());

        Ball ball = box3.getPen();
        ball.draw();
    }
}

2개 이상의 generic

class Box2<T1, T2>{
    T1 obj1;
    T2 obj2;

    public void setObj1(T1 obj1) {
        this.obj1 = obj1;
    }
    public void setObj2(T2 obj2) {
        this.obj2 = obj2;
    }
    public T1 getObj1() {
        return obj1;
    }
    public T2 getObj2() {
        return obj2;
    }
}
public class Ex03 {

    public static void main(String[] args) {
        Box2<Pencil1, Ballpen1> box = new Box2<Pencil1, Ballpen1>();

        box.setObj1(new Pencil1());
        box.setObj2(new Ballpen1());

        Pencil1 pen1 = box.getObj1();
        pen1.draw();

        Ballpen1 pen2 = box.getObj2();
        pen2.draw();
    }
}

매개변수를 사용한 generic 타입 - 메서드에서의 generic

class Box3{
    public static <T>T func01(T pen) {
        Box1<T> box = new Box1<T>();
        box.setPen(pen);
        return box.getPen();
    }
}

public class Ex04 {

    public static void main(String[] args) {
        Pencil pen = Box3.<Pencil>func01(new Pencil());
        pen.draw();

        Ballpen pen1 = Box3.<Ballpen>func01(new Ballpen());
        pen1.draw();
    }
}
  • => generic을 명시하지 않아도 매개변수의 유형을 통해 추론이 가능한다.
Pencil pen = Box3.func01(new Pencil());
pen.draw();

generic의 표현 방식

class Box05<T>{
    T t;
    public void setT(T t) {
        this.t = t;
    }
    public T getT() {
        return t;
    }
}

public class Ex05 {

    public static void main(String[] args) {
        Ballpen1 pen1 = new Ballpen1();
        Pencil1 pen2 = new Pencil1();

        // generic의 추론 타입(jdk 1.7~)

//        Box05<Ballpen1> box1 = new Box05(); // - generic이 붙지 않은 객체(Object)를 생성한다. - Ballpen만 사용할 수 있음

//        Box05<> box1 = new Box05<Ballpen1>(); // - generic이 붙지 않은 효과와 같음 - 사용할때 캐스팅이 필요함 

//        Box05<Ballpen1> box1 = new Box05<>(); // 생성자의 generic을 생략 가능 

//        Box05<?> tmp = new Box05<>(); // Wild - generic을 붙이지만 타입의 결정을 미룬다.\
//        Box05<Ballpen1> box1 = (Box05<Ballpen1>) tmp; // wild가 붙은 생성자의 generic을 결정함

        Box05<Pen1> box1 = new Box05<>(); // 생성자의 generic을 생략 가능 

        box1.setT(pen1);
        Pen1 pen3 = box1.getT();
        pen1.draw();

        box1.setT(pen2);
        Pen1 pen4 = box1.getT();
        pen4.draw();
    }
}

generic의 제약 방식

class Box05<T extends Pen>{ // Pen을 상속받는 클래스만 붙일 수 있다. 
public void func01(java.util.List<? super Number> list) { // Number 이상의 클래스만 붙일 수 있다. 
java.util.List<Number> list = null; // 가능
java.util.List<Object> list = null; // 가능
java.util.List<Integer> list = null; // 불가능 

box1.func01(list);

(이론적으로) 순서가 없는 자료구조

  • 중복 불가

Enumeration

  • 오직 열람을 위해 존재하고 안에 존재하는 element들을 수정할 수 없다.
// 순서가 있는 자료구조 
Vector vec = new Vector();

vec.addElement("첫번째");
vec.addElement("두번째");
vec.addElement("세번째");
vec.addElement("네번째");
vec.addElement("다섯번째");
for(int i = 0; i < vec.size(); i++) {
    System.out.println(vec.elementAt(i));
}

System.out.println("-----------------------------");
// 순서가 없는 자료구조 
Enumeration eles = vec.elements();
// while(eles.hasMoreElements()) {
// System.out.println(eles.nextElement()); // 다음 엘리먼트를 가리킴 
// }
System.out.println(eles.nextElement()); // 다음 엘리먼트를 가리킴 
System.out.println(eles.nextElement()); // 다음 엘리먼트를 가리킴 
System.out.println(eles.nextElement()); // 다음 엘리먼트를 가리킴 
// Enumeration으로는 다시 처음으로 돌아가는 방법이 없다.

System.out.println("-----------------------------");
eles = vec.elements(); // 다시 엘리먼트를 받아내는 방법 밖에.
System.out.println(eles.nextElement());

Stack

// 후입선출 (LIFO)
Stack list = new Stack();
list.push("첫번째");
list.push("두번째");
list.push("세번째");
list.push("네번째");
//        
// System.out.println(list.pop()); // 네번째
// System.out.println(list.peek()); // 세번째
// System.out.println(list.pop()); // 세번째
// System.out.println(list.peek()); // 두번째
// System.out.println(list.pop()); // 두번째 
// System.out.println(list.peek()); // 첫번째
// System.out.println(list.pop()); // 첫번째 
// System.out.println(list.empty());
System.out.println(list.search("두번째")); // 3
System.out.println("---------------------");
while(!list.empty()) {
    System.out.println(list.pop());
}

Set

// 순서가 없는
java.util.Set<String> set = new java.util.HashSet<>();
set.add("첫번째");
set.add("두번째");
set.add("세번째");
set.add("네번째");
Iterator<String> ite = set.iterator(); // 열람을 하기 위한 별도의 객체 
// System.out.println(ite.next());
// System.out.println(ite.next());
// System.out.println(ite.next());
// System.out.println(ite.next());
// System.out.println(ite.hasNext());
while(ite.hasNext()) {
    String msg = ite.next();
    System.out.println(msg);
}

Set을 이용한 자료의 중복 제거

List<Integer> list = new ArrayList<>();
list.add(1111);
list.add(2222);
list.add(2222);
list.add(1111);

Set<Integer> set = new HashSet<>(list);
terator<Integer> ite = set.iterator();
while(ite.hasNext()) {
    System.out.println(ite.next());
}
Set<String> set = new HashSet<>();
set.add("첫번째");
set.add("첫번째");
set.add("두번째");
set.add("첫번째");
List<String> list = new ArrayList<>(set);
for(int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

중복값 검사를 위한 Set의 종류

// Set을 사용하는 건 중복값검사를 위해서이다. 
Set<Integer> set;
// set = new HashSet<>();
// set = new LinkedHashSet<>();
set = new TreeSet<>(); // integer 사용 시 순서대로 나옴 - 이진트리구조를 이용한 자료의 정렬 
set.add(3333);
set.add(1111);
set.add(4444);
set.add(2222);

Iterator<Integer> ite = set.iterator();
while(ite.hasNext()) {
System.out.println(ite.next());
    }

TreeSet

  • 이진트리구조를 이용한 자료의 정렬
  • 이진트리 방식을 사용하면 검사를 수행해야 할 획수가 획기적으로 줄어든다.
class Car implements Comparable<Car>{
    String color;
    public Car(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return color + "색 차";
    }
    @Override
    public int compareTo(Car o) { // TreeSet의 검사를 수행하기 위해 Comparable이 수반돼야 한다. 
        return this.color.compareTo(o.color);
    }
}

public class Ex12 {

    public static void main(String[] args) {

        Set<Car> set;
        set = new TreeSet<>(); // 이진트리구조를 이용해 중복을 검사  
        set.add(new Car("빨강"));
        set.add(new Car("주황"));
        set.add(new Car("노랑"));
        set.add(new Car("노랑"));
        set.add(new Car("초록"));

        Iterator<Car> ite = set.iterator();
        while(ite.hasNext()) {
            System.out.println(ite.next());
        }
    }

HashSet

class Car implements Comparable{
    String color;
    public Car(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return color + "색 차";
    }
    public int hashCode() { // 해시 코드의 주소를 같게 만듬
        if(color.contentEquals("빨강")) return 1111;
        if(color.contentEquals("노랑")) return 2222;
        return super.hashCode();
    }
    public boolean equals(Object obj) {
        return true;
    }


}

public class Ex12 {

    public static void main(String[] args) {

        Set<Car> set;
        set = new HashSet<>(); // 해시코드(메모리의 주소)를 비교해 중복을 검사 
        set.add(new Car("빨강"));
        set.add(new Car("빨강"));
        set.add(new Car("주황"));
        set.add(new Car("노랑"));
        set.add(new Car("노랑"));
        set.add(new Car("초록"));

        Iterator<Car> ite = set.iterator();
        while(ite.hasNext()) {
            System.out.println(ite.next());
        }
    }
}
  • List와 Set은 서로 복사가 가능하다.

Map

  • 순서가 없는 자료구조
  • 순서는 Key를 가지고 value를 뽑아낸다. - Entry set이라는 객ㅊ?로 가지고 있다.
  • Map은 collection을 상속받고 있지 않지만 Set과 List의 기능을 가지고 있다.
  • Map은 Map 끼리만 복사가 가능하다.
Map<String, String> map = new HashMap<>();
// key, value
// key : set (중복 불허)
// value : list (중복 허용)
map.put("key1", "val1");
map.put("key2", "val2");
map.put("key3", null);
map.put(null, "val3");
// map.put(null, null); // value는 중복이 가능하나 Key는 중복이 불가능하다.

System.out.println(map.get("key1"));
System.out.println(map.get("key2"));
System.out.println(map.get("key3"));
System.out.println(map.get(null));        
System.out.println(map.get("key4")); // null

Map에서의 수정/삭제

map.replace("key2", "value222");
map.remove("key2", "value222"); // value가 같을 때만 삭제를 수행  
map.remove("key2");

Map에서의 반복

Map<String, String> map = new HashMap<>();
map.put("key1", "val1");
map.put("key2", "val2");
map.put("key3", "val3");
map.put("key4", "val4");

Set<Entry<String, String>> set = map.entrySet();
Iterator<Entry<String, String>> ite = set.iterator();
while(ite.hasNext()) {
    Entry<String, String> ent = ite.next();
    System.out.println("key = " + ent.getKey() + ", val = " + ent.getValue());
}

System.out.println("-----------------------");
Set<String> keys = map.keySet();
Iterator<String> ite2 = keys.iterator();
while(ite2.hasNext()) {
    String key = ite2.next();
    System.out.println("key = " + key + ", value = " + map.get(key));
}