제네릭

현서·2025년 5월 27일
1

자바

목록 보기
17/32
post-thumbnail

1. 제네릭(Generic)

자바에서 클래스나 메서드를 선언할 때 사용할 데이터 타입을 나중에 지정할 수 있도록 하는 기능

1. 제네릭을 사용하는 이유

  • 타입 안정성 : 컴파일 시점에 타입을 검사하여 오류를 줄일 수 있다.
  • 형변환 제거 : Object로 저장 후 꺼낼 때 형변환을 하지 않아도 된다.
  • 코드 재사용성 증가 : 다양한 타입에 대해 같은 로직을 사용할 수 있다.
class 클래스이름<T> {
    // T는 타입 파라미터 (예: String, Integer 등)
    private T 변수;

    public void set(T 변수) {
        this.변수 = 변수;
    }

    public T get() {
        return 변수;
    }
}

제네릭을 사용하지 않은 경우

Object를 사용하면 꺼낼 때 형변환(casting)이 필요하며, 실행 중(ClassCastException) 오류가 날 수 있다.

package lesson06;

class ObjectBox {
    private Object item;
    public void set(Object item){
        this.item = item;
    }
    public Object get(){
        return item;
    }
}

public class Ex10_Main {
    public static void main(String[] args) {
        ObjectBox box = new ObjectBox();
        box.set("사과");
        Object obj = box.get();
        String fruit = (String) obj;
        System.out.println("과일: " + fruit);

        box.set(123);
        obj = box.get();
        // String fruit = (String) obj; // 잘못된 형변환 시 에러 발생
    }
}

제네릭을 사용한 경우

제네릭을 사용하면 저장할 때 타입을 제한할 수 있고, 꺼낼 때 형변환이 필요 없다.

package lesson06;

class Box<T> {
    private T item;
    public void set(T item){
        this.item = item;
    }
    public T get(){
        return item;
    }
}

public class Ex11_Main {
    public static void main(String[] args) {
        Box<String> stringBox = new Box<>();
        stringBox.set("바나나");
        String fruit = stringBox.get(); // 형변환 없이 꺼냄
        System.out.println("과일: " + fruit);

        Box<Integer> intBox = new Box<>();
        intBox.set(100);
        int number = intBox.get(); // 형변환 없이 꺼냄
        System.out.println("숫자: " + number);
    }
}

2. 제네릭 클래스

package lesson06;

/*
    제네릭 타입 문자
    T: Type(주로 객체 타입)
    E: Element(컬렉션 요소 타입)
    K: Key(맵의 키 타입)
    V: Value(맵의 값 타입)
    U: 두 번째, 보조 타입(보통 T 다음)
*/

class Person<T, U>{
    private T name;
    private U age;
    public Person(T name, U age){
        this.name = name;
        this.age = age;
    }
    public void printInfo(){
        System.out.println("이름: " + name + ", 나이: " + age);
    }
}

public class Ex12_Main {
    public static void main(String[] args) {
        Person<String, Integer> p1 = new Person<>("김사과",20);
        p1.printInfo();
        Person<String, Double> p2 = new Person<>("김사과",25.5);
        p2.printInfo();
    }
}

3. 제네릭 메서드

package lesson06;

class Printer{
    public <T> void print(T item){
        System.out.println("출력: " + item);
    }
}

public class Ex13_Main {
    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print("안녕");
        printer.print(2);
        printer.print(3.14);
        printer.print(true);
    }
}

2. 컬렉션 프레임워크(Collection Framework)

자바에서 데이터를 효율적으로 저장하고 처리할 수 있도록 다양한 자료구조(리스트, 집합, 맵 등)와 알고리즘을 제공하는 표준화된 클래스 집합.

배열보다 더 유연하고 강력한 방식으로 데이터를 추가, 삭제, 검색할 수 있으며, 제네릭을 활용해 타입 안정성도 확보할 수 있다.

visualgo ← 이해 돕는 사이트

1. List 계열

  • 순서(인덱스)를 유지하며 저장
  • 중복된 요소 허용
  • 요소를 인덱스로 접근 가능 (list.get(0) 형태)

ArrayList 내부적으로 배열 사용, 빠른 검색, 느린 삽입/삭제 (특히 중간 삽입)
LinkedList 이중 연결 리스트 구조, 빠른 삽입/삭제, 느린 검색
Vector ArrayList와 유사하지만 동기화 처리 되어 멀티스레드에 적합
Stack Vector를 상속한 후 LIFO 구조를 따르는 클래스 (push/pop 지원)

package lesson06;

import java.util.ArrayList;

public class Ex14_Main {
    public static void main(String[] args) {
        ArrayList<String> students = new ArrayList<>();
        students.add("김사과");
        students.add("반하나");
        students.add("오렌지");

        students.add(1,"이메론");
        System.out.println(students);
        for(String name: students){
            System.out.println("- " + name);
        }

        String student = students.get(2);
        System.out.println("\n2번 인덱스의 학생: " + student);

        students.set(2, "배애리"); // 2번 인덱스의 값을 바꿈
        System.out.println("\n수정 후 2번 인덱스의 학생: " + students.get(2));

        students.remove("이메론");
        System.out.println(students);
        students.remove(0);
        System.out.println(students);

        System.out.println("\n현재 학생 수: " + students.size());

        System.out.println("\n최종 학생 목록");
        for(int i = 0; i<students.size(); i++){
            System.out.println(students.get(i));
        }
    }
}
package lesson06;

import java.util.LinkedList;

public class Ex15_Main {
    public static void main(String[] args) {
        LinkedList<String> ll = new LinkedList<>();

        ll.add("김사과");
        ll.add("반하나");
        ll.add("오렌지");

        ll.addFirst("이메론");
        System.out.println(ll);

        System.out.println("현재 대기열:");
        for(String s:ll){
            System.out.println("- " + s);
        }

        while(!ll.isEmpty()){
            ll.removeFirst();
            System.out.println("결과: " + ll);
        }

        System.out.println("남은 요소: " + ll.size());
    }
}
package lesson06;

import java.util.Vector;

public class Ex16_Main {
    public static void main(String[] args) {
        Vector<Integer> scores = new Vector<>();
        scores.add(90);
        scores.add(85);
        scores.add(78);
        scores.add(92);
        scores.add(88);

        System.out.println("전체 학생 점수: ");
        for(int i = 0; i<scores.size(); i++){
            System.out.println("- " + getName(i) + " : " + scores.get(i) + "점");
        }
        int sum = 0;
        for(int score: scores){
            sum += score;
        }
        double average = (double)sum/scores.size();
        System.out.println("\n전체 평균 점수: " + average);

        scores.set(2, 80);
        System.out.println("\n오렌지 점수 수정 후: " + scores.get(2) + "점");

        scores.remove(scores.size()-1);
        System.out.println("\n마지막 학생(배애리) 삭제 후 학생 수: " + scores.size());
    }

    public static String getName(int index){
        switch(index){
            case 0: return "김사과";
            case 1: return "반하나";
            case 2: return "오렌지";
            case 3: return "이메론";
            case 4: return "배애리";
            default: return "이름없음";
        }
    }
}

2. Set 계열

  • 중복을 허용하지 않음
  • 순서가 없음 (일반적으로 입력 순서를 보장하지 않음)
  • 하나의 집합(수학의 Set 개념과 유사)

HashSet 순서를 유지하지 않음, 가장 일반적인 Set
LinkedHashSet 입력 순서를 유지함
TreeSet 자동 정렬됨 (오름차순), 내부적으로 트리 구조 사용

package lesson07;

import java.util.HashSet;

public class Ex01_Main {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<String>();
        set.add("김사과");
        set.add("반하나");
        set.add("오렌지");
        set.add("이메론");
        set.add("배애리");
        // 중복 데이터
        set.add("김사과");
        set.add("배애리");

        System.out.println(set);

        System.out.println("출석한 학생 명단: ");
        for (String name: set){
            System.out.println("- "+name);
        }

        System.out.println("오렌지 출석 여부: " + set.contains("오렌지"));
        System.out.println("박수박 출석 여부: " + set.contains("박수박"));

        set.remove("이메론");
        for (String name: set){
            System.out.println("- "+name);
        }
    }
}
package lesson07;

import java.util.TreeSet;

public class Ex02_Main {
    public static void main(String[] args) {
        TreeSet<String> set = new TreeSet<>();
        set.add("김사과");
        set.add("반하나");
        set.add("오렌지");
        set.add("이메론");
        set.add("배애리");

        set.add("김사과");
        System.out.println(set);

        for (String name : set){
            System.out.println("- " + name);
        }

        System.out.println("오렌지보다 앞에 오는 이름: " + set.lower("오렌지"));
        System.out.println("오렌지보다 뒤에 오는 이름: " + set.higher("오렌지"));
    }
}

TreeSet 특징
정렬 저장 자동으로 오름차순 정렬 (String, Integer 등 Comparable 필요)
중복 허용 ❌ 허용하지 않음
탐색 기능 lower(), higher(), floor(), ceiling() 등
성능 이진 탐색 트리 기반 → 삽입, 삭제, 검색 모두 O(log n)
정렬 기준 변경 Comparator를 생성자에 전달하여 커스텀 정렬 가능

📌 O(log n) 뜻:

  • 시간 복잡도(Time Complexity)를 나타내는 표현 중 하나.
    알고리즘이 얼마나 빠른지를 설명할 때 사용
  • n이 입력 데이터의 크기일 때,
    알고리즘이 입력을 처리하는 데 걸리는 시간이 로그(log)에 비례한다는 뜻.
    (log는 보통 log₂(n) (2를 밑으로 한 로그)를 의미.)

🔍 왜 빠른가?

  • 한 번 비교할 때마다 검색 범위가 절반으로 줄기 때문이다.
    예를 들어 1000개의 데이터가 있으면:
    1회 → 500개,
    2회 → 250개,
    ...
    약 10번만 비교하면 원하는 값을 찾을 수 있다.
package lesson07;

import java.util.TreeSet;

class Student implements Comparable<Student>{
    String name;
    int score;
    public Student(String name, int score){
        this.name = name;
        this.score = score;
    }

    @Override
    public int compareTo(Student o) {
        /*
            a < b : -1 (a가 앞쪽 (왼쪽)에 위치)
            a == b : 0 (순서 변화 없음)
            a > b : 1 (a가 뒤쪽 (오른쪽)에 위치)
        */
       // return Integer.compare(this.score, o.score); // 점수로 오름차순
        return Integer.compare(o.score, this.score); // 점수로 내림차순
    }

    @Override
    public String toString() {
        return name + " (" + score + "점)";
    }
}

public class Ex03_Main {
    public static void main(String[] args) {
        TreeSet<Student> set = new TreeSet<>();
        set.add(new Student("김사과", 90));
        set.add(new Student("반하나", 85));
        set.add(new Student("오렌지", 95));
        set.add(new Student("이메론", 92));
        set.add(new Student("배애리", 85));  // 같은 점수 → 중복 간주 안되지만 순서 주의

        for(Student s : set){
            System.out.println("- " + s);
        }
    }
}
package lesson07;

import java.util.Comparator;
import java.util.TreeSet;

class Ex04_Student {
    String name;
    int score;
    public Ex04_Student(String name, int score){
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return name + " (" + score + "점)";
    }
}

public class Ex04_Main {
    public static void main(String[] args) {
        Comparator<Ex04_Student> comparator = (a, b) -> b.name.compareTo(a.name); // 내림차순
        TreeSet<Ex04_Student> set = new TreeSet<>(comparator);
        set.add(new Ex04_Student("김사과", 90));
        set.add(new Ex04_Student("반하나", 85));
        set.add(new Ex04_Student("오렌지", 95));
        set.add(new Ex04_Student("이메론", 92));
        set.add(new Ex04_Student("배애리", 85));

        for(Ex04_Student s : set){
            System.out.println("- " + s);
        }
    }
}

3. Map 계열

  • 데이터를 Key-Value 쌍으로 저장
  • Key는 중복될 수 없음, Value는 중복 가능
  • 값을 검색할 때는 key를 사용 (map.get("name"))

HashMap 가장 많이 사용됨. 키 순서 없음
LinkedHashMap 입력 순서 유지
TreeMap 키 기준 정렬 (Comparable 또는 Comparator 필요)
Hashtable HashMap과 유사하나, 동기화 지원, null 키 불가

package lesson07;

import java.util.Comparator;
import java.util.TreeSet;

class Ex04_Student {
    String name;
    int score;
    public Ex04_Student(String name, int score){
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return name + " (" + score + "점)";
    }
}

public class Ex04_Main {
    public static void main(String[] args) {
        Comparator<Ex04_Student> comparator = (a, b) -> b.name.compareTo(a.name); // 내림차순
        TreeSet<Ex04_Student> set = new TreeSet<>(comparator);
        set.add(new Ex04_Student("김사과", 90));
        set.add(new Ex04_Student("반하나", 85));
        set.add(new Ex04_Student("오렌지", 95));
        set.add(new Ex04_Student("이메론", 92));
        set.add(new Ex04_Student("배애리", 85));

        for(Ex04_Student s : set){
            System.out.println("- " + s);
        }
    }
}
profile
The light shines in the darkness.

0개의 댓글