본문 바로가기
JAVA

JAVA 12일차

by teg0 2025. 8. 21.

제네릭

제네릭을 사용하지 않고 Object와 같은 넓은 범위를 수용할 수 있는 필드 변수의 타입을 사용 시

-> 형반환이 필요, 런타임 오류 발생

클래스나 메서드가 사용할 데이터타입을 컴파일 시점에 지정할 수 있도록 지원하는 문법

-> 매개타입(객체 생성시 타입을 전달받아 결정)

 

public static void main(String[] args) {
    //제네릭 클래스의 매개타입을 전달하지 않으면 기본적으로 Object로 설정
    Box aBox = new Box<>();
    aBox.setValue("value");
    //int num = aBox.getValue(); // 반한시에도 Object로 반환
    int num = (Integer)aBox.getValue(); //형변환

    System.out.println(aBox.getValue());

    Box<Integer> iBox = new Box<>();
    //iBox.setValue("value"); 매개타입이 Integer이므로 Stirng 전달불가
    iBox.setValue(100);
    int num2 = iBox.getValue(); //형변환 불필요

    Integer[] arr = new Integer[5];
    iBox.setArr(arr);

    //iBox.setArr(new String[] {"1", "2"}); String이라서 불가능


}

제네릭은 형변환을 여러번하는 과정을 없애고, 매개 타입에 맞는 데이터만 입력할 수 있도록 해주는 편리한 문법이다.

 

컬렉션 

자료구조 개념이 내장되어 있는 클래스로 자바에서 제공하는 라이브러리

자료구조 : 데이터를 보다 효율적으로 관리(추가, 삭제, 조회, 정렬, 수정)할 수 있도록 해주는 구조

 

List

순서가 존재하며, 중복이 가능하다.
ArrayList(배열기반), LinkedList(노드기반), Vector, Stack(Vector기반 LIFO구조)

 

장점

  1. 크기제약 X,  지정된 크기보다 더 많이 추가해도 에러가 발생하지 않음.
  2. 여러 타입 보관가능, 다양한 타입의 데이터를 담을 수 있음. 
public static void main(String[] args) {
    List list = new ArrayList(); //크기를 지정하지 않아도 됨

    System.out.println(list); //빈 배열상태

    //1. add(E e) : 리스트 공간 끝에 전달된 데이터를 추가
    list.add(new Human("이무진", 26));
    list.add("이무진"); //여러타입을 저장할 수 있음.
    list.add(new Human("이무진", 26));
    list.add(new Human("이무진", 26));

    System.out.println(list);

    //2. add(int index, E e) : 직접 인덱스를 지정해서 해당위치 데이터를 추가
    list.add(1, new Human("홍길동", 20));
    System.out.println(list);

    //3. remove(int index) : 해당 인덱스 위치의 데이터를 삭제시켜주는 메서드
    list.remove(1);
    System.out.println(list);

    //4. remove(E e) : 객체를 직접 지정해서 삭제
    list.remove("이무진");
    System.out.println(list);

    list.remove(new Human("이무진", 26));
    System.out.println(list);

    //5. set(int index, E e) : 해당 인덱스의 값을 전달받은 e객체로 덮어씌움
    list.set(0, new Human("홍길동", 23));
    System.out.println(list);

    //6. size() : 리스트의 사용중인 사이즈를 반환
    System.out.println(list.size());

    //7. get(int index) : 해당 인덱스의 객체를 반환
    System.out.println(list.get(1));

    //8. addAll(Collection c) : 컬렉션을 통째로 뒤에 추가할 수 있음
    List sub = new ArrayList();
    sub.add(new Human("이무진", 26));
    sub.add(new Human("홍길동", 23));
    list.addAll(sub);
    System.out.println(list);

    //9. isEmpty() : boolean -> 컬렉션이 비어있는지 확인
    System.out.println(list.isEmpty());

    //10. clear() : 컬렉션의 내용을 전부 비워버리는 메서드
    list.clear();
    System.out.println(list.isEmpty());
    System.out.println(list);

    //리스트 전체 접근 방법
    for(int i=0; i<list.size(); i++) {
        System.out.println(list.get(i));
    }

    for(Object h : list) {
        System.out.println(h);
    }

    //List list = new LinkedList();여도 메서드는 동일

}

 

Stack

public static void main(String[] args) {		
    //Stack
    Stack<String> stack = new Stack<>();

    //push() 데이터 추가
    stack.push("첫번째");
    stack.push("두번째");
    stack.push("세번째");

    System.out.println(stack);

    //peek() 맨 위 데이터를 확인
    System.out.println(stack.peek());

    //pop() 데이터 꺼내기
    String data = stack.pop();
    System.out.println(data);
    System.out.println(stack);

    //검색 search(E e) : 데이터 검색 후 존재하면 위치 반환(위에서부터 센다) -> equals를 사용하여 비교검색
    System.out.println(stack.search("첫번째"));

    //stack 전체 꺼내기
    while(!stack.isEmpty()) {
        System.out.println("꺼낸 값 : " + stack.pop());
    }

}

컬렉션에서 List나 Stack은 equals를 오버라이딩해서 사용해야 한다.

@Override
public boolean equals(Object obj) {
    if(obj instanceof Human) {
        Human h = (Human)obj;
        return this.name.equals(h.getName()) && this.age == h.getAge();
    }
    return false;
}

 

Set

순서가 없고, 중복을 허용하지 않는 자료구조

index개념이 없어서 위치기반 접근(get(index))이 불가

  • HashSet : 일반적인 해시알고리즘이 적용된 set
  • LinkedHashSet : hashSet + 순서유지
  • TreeSet : 자동정렬 기능 제공
public static void main(String[] args) {
    //생성
    Set<Human> set = new HashSet<>();

    //추가
    set.add(new Human("홍길동", 20));
    set.add(new Human("홍길동", 25));
    set.add(new Human("홍길서", 20));
    set.add(new Human("홍길남", 25));
    System.out.println(set);
    //set에 저장해서 사용하는 객체(Human)는 equals와 hashcode를 오버라이딩해야한다.
    //set은 hashCode()로 분류 후 equals()로 바교해서 중복값을 검사함

    set.add(new Human("홍길동", 20));
    set.add(new Human("홍길동", 25));
    System.out.println(set); //동일객체는 추가가 되지 않음

    Human h1 = new Human("홍길남", 25);
    Human h2 = new Human("홍길남", 25);

    //동일객체 : (h1.equals(h2) && h1.hashCode() == h2.hashCode())
    //객체마다의 정의된 hashCode와 equals의 결과가 모두 일치하는 객체
    //equals와 hashcode를 오버라이딩하지 않으면 Object의 equals와 hashcode를 사용
    //Object의 equals -> 주소값 비교
    //Object의 hashCode -> 주소값을 가지고 10진수형태의 해시값을 구한것

    //contains() 요소에 포함여부 확인
    System.out.println("홍길남이 존재? : " + set.contains(h2)); //true

    //remove(E e)
    set.remove(h1);
    System.out.println("삭제 후 : " + set);

    //size()
    System.out.println("size : " + set.size());

    //set의 모든 요소에 순차적으로 접근하는 방법
    //set은 index가 없기 때문에 get()을 사용할 수 없음

    //1. for ~ each
    for(Human h : set) {
        System.out.println(h);
    }

    //2. ArrayList에 담아서 반복 -> addAll(Collection c)
    ArrayList list = new ArrayList();
    list.addAll(set);
    for (int i=0; i<list.size(); i++) {
        System.out.println(list.get(i));
    }

    //3. Iterator(반복자 인터페이스)를 활용
    //컬렉션에 저장된 요소를 순차적으로 접근하기 위한 인터페이스
    //순서가 없는 set같은 자료구조를 탐색할 때 반드시 필요
    //hasNext() : 다음 읽을 요소가 있으면 true, 없으면 false
    //next() : 다음 요소를 반환
    Iterator<Human> it = set.iterator();
    while(it.hasNext()) {
        Human h = it.next(); //다음 요소 꺼내기
        System.out.println(h);
    }

}

Set을 사용하려면 equals뿐만이 아니라 hashcode도 오버라이딩을 해야 한다.

@Override
public boolean equals(Object obj) {
    if(obj instanceof Human) {
        Human h = (Human)obj;
        return this.name.equals(h.getName()) && this.age == h.getAge();
    }
    return false;
}

@Override
public int hashCode() {
//	return ("" + name + age).hashCode(); -> String의 HashCode메서드 이용(문자열 값에 따라 달라짐)
    return Objects.hash(name, age); //Object에 hash메서드를 이용하는 방법(비교를 원하는 모든 인자를 전달 가능) 
}

 

Map

key와 value를 쌍으로 저장하는 자료구조

key는 중복 불가, value는 중복 가능

HashMap(가장 보편적이고 속도향상), LinkedHashMap(입력순서 보장), TreeMap(정렬된 key순서 유지)

public static void main(String[] args) {
    Map<Integer, Human> hMap = new HashMap<>();

    //1. put() : map에 key, value 쌍으로 값을 추가
    hMap.put(10, new Human("홍길동", 20));
    hMap.put(20, new Human("홍길서", 30));
    hMap.put(30, new Human("홍길남", 40));
    hMap.put(40, new Human("홍길북", 50));
    hMap.put(40, new Human("홍길", 60)); //동일한 key 사용시 값을 덮어씀
    System.out.println(hMap); //저장되는 순서 유지 안됨

    //2. get(key) : 해당 key의 value를 반환
    System.out.println(hMap.get(30));

    //3. size() : 담겨있는 객체 수
    System.out.println("size : " + hMap.size());

    //4. remove(key) : 해당 key의 값을 찾아서 쌍으로 제거
    hMap.remove(40);
    System.out.println(hMap);


    //map의 전체요소를 탐색하는 방법
    //Iterator 이용 X
    //for each 이용 X
    //다른 자료구조로 변경 후 반복
    //1. key를 모아서 Set자료 구조 형태로 반환
    Set keySet = hMap.keySet(); //모든 key를 Set에 담아서 반환
    System.out.println(keySet);
    for(Object key : keySet) {
        System.out.println("키 : " + key + "값 : " + hMap.get(key));
    }

    //2. entrySet을 이용한 전체 탐색
    //Map은 key와 value를 쌍으로 저장하기 때문에 단순하게 keySet(), values()만으로는 
    //한번에 key와 value를 가져올 수 없다.
    //Set<Map.Entry<K, V>>
    Set entrySet = hMap.entrySet();
    for(Object entry : entrySet) {
        Entry e = (Entry)entry;
        System.out.println(e.getKey() + " " + e.getValue());
    }
}

 마찬가지로 Map도 equals와 hashCode를 오버라이딩해야 한다.(위 Set에서 사용한 equals와 hashCode를 사용)

 

'JAVA' 카테고리의 다른 글

JAVA 13일차  (1) 2025.08.22
JAVA 11일차  (0) 2025.08.20
JAVA 9일차  (1) 2025.08.18
JAVA 8일차  (3) 2025.08.14
JAVA 7일차  (3) 2025.08.13