backend
  • README
  • DOCS
    • Java Docs
    • Servlet Docs
    • JSP Docs
    • DB & SQL Docs
    • Spring Boot Docs
    • Spring Security Docs
    • AWS Docs
  • 설치하기
    • Intellij 설정
  • 자바
    • 01 Java란?
    • 02 자바 시작하기
    • 03 자료형과 연산자
    • 04 제어문
    • 05 메소드
    • 06 클래스 기초
      • Static 보충자료
      • 패키지 보충자료
    • 07 객체지향 프로그래밍
    • 08 클래스 더 알아보기
      • 열거형 ENUM 보충자료
    • 09 클래스와 자료형
      • 다형성 보충자료
      • 제네릭 보충자료
    • 10 컬렉션 프레임워크
      • 컬렉션 프레임워크 보충자료
    • 11 람다식과 함수형 프로그래밍
      • 람다식 보충자료
    • 12 오류 대비하기
      • 오류 보충자료
    • 13 멀티태스킹
      • 멀티태스킹 보충자료
    • 교재보충
      • java.lang
  • 스프링
    • 서블릿, JSP
      • 05 Servlet(서블릿)
        • 서블릿 보충자료
        • 서블릿 추가코드
        • XML, YAML, JSON
      • 06 JSP(자바 서버 페이지)
        • JSP 보충자료
      • 07 JSTL(JSP 스탠다드 태그 라이브러리)
        • JSTL 보충자료
      • 08 Cookie(쿠키), Session(세션)
      • 09 서블릿,필터,리스너
        • 서블릿,필터,리스너 보충자료
      • 11 도서관리 프로젝트 실습
    • Spring Boot
      • 01 스프링 등장 배경, 객체지향
        • 스프링 등장 배경, 객체지향 보충자료
      • 02 IOC(제어의 역전), DI(의존성 주입)
        • IOC 보충자료
        • DI 보충자료
      • 03 스프링 구조
        • 스프링 구조 보충설명
      • 04 테스트코드 실습
      • 05 스프링 빈 설정
        • 스프링 빈 설정 보충자료
      • 06 싱글톤
        • 싱글톤 보충 자료
      • 07 스프링 빈 자동설정
        • 스프링 빈 자동설정 보충자료
      • 08 빈 생명주기
        • 빈 생명주기 보충자료
      • 09 빈 스코프
        • 빈 스코프 보충자료
      • 10 스프링 MVC
        • 스프링 MVC 보충자료
        • 데이터베이스 연동에 필요한 부분
      • 11 Validation(검증)
        • Validation(검증) 보충자료
      • 12 Bean Validation(빈검증)
        • Bean Validation(빈검증) 보충자료
      • 13 예외처리
        • 예외처리 보충자료
      • 14 타입변환
      • 15 JDBC(Java Database Connectivity)
      • 16 커넥션풀
      • 17 트랜잭션
        • 트랜잭션 보충자료
      • 18 JDBC 템플릿 활용
      • 19 MyBatis
      • 20 JPA(Java Persistence API)
      • 22 게시판 프로젝트 실습
    • Spring Security
      • 보안(Security)
      • Spring Security
      • 2. Spring Security 알아보기
        • 보안 위협 실제 사례와 방어 전략
      • 3. Spring Security 기본 동작 흐름
      • 4. Spring Security로 인증 권한 추가하기
        • Spring Security의 인증 및 인가
      • 5. Spring Security에서 세션 관리하기
        • 세션(Session)과 쿠키(Cookie) 비교, 토큰(Token)과의 관계
        • 해싱 및 해싱알고리즘
        • base64
      • 6. Spring Security 악용 보호
        • SameSite
      • 7. Spring Security로 인가 권한 추가하기
      • 8. Bcrypt(비크립트) 암호화
      • OAuth2 적용하기
  • 네트워크
    • HTTP
    • OSI 7계층
  • DB&SQL
    • 01 Database(데이터베이스)와 SQL 개요
    • 02 관계형 모델
    • 03 집합
    • 04 JOIN 연산
    • 05 MySQL
      • 세이브포인트
      • DBeaver, Mysql 오토커밋 설정 관련
    • 06 SQL 기초
      • 예시데이터 쿼리문
    • 07 SQL 실습
      • 실습 스키마
    • 08 Join 활용
      • 실습스키마
    • 09 SQL 활용
      • 실습스키마
    • 10 정규화
      • 실습 스키마
    • 데이터타입
    • 예시 프로젝트 스키마 구성
  • AWS
    • SSL 연결하기
    • 보충설명
Powered by GitBook
On this page
  • Object 클래스
  • 1. Object 클래스란?
  • Object 클래스의 주요 메소드
  • 1. equals(Object obj)
  • 2. hashCode()
  • 3. toString()
  • Wrapper 클래스
  • 1. Wrapper 클래스란?
  • 2. 기본 자료형과 대응되는 Wrapper 클래스
  • 3. Wrapper 클래스의 사용 예시
  • 박싱(Boxing)
  • 언박싱(Unboxing)
  • 기본 자료형을 객체로 변환
  • 4. 오토박싱과 오토언박싱
  • 오토박싱: 기본 자료형을 자동으로 Wrapper 객체로 변환하는 과정.
  • 오토언박싱: Wrapper 객체를 자동으로 기본 자료형으로 변환하는 과정.
  • 5. Wrapper 클래스의 주요 메소드
  • 6. Wrapper 클래스의 활용 예시
  • 1. 컬렉션 클래스와의 사용
  • 2. 상수로서의 사용
  • 정리
  • 제네릭
  • 1. 제네릭을 사용하는 이유
  • 2. 제네릭의 기본 문법
  • 3. 제네릭 클래스
  • 제네릭 클래스 정의
  • 제네릭 클래스 사용
  • 4. 제네릭 메소드
  • 제네릭 메소드 정의
  • 제네릭 메소드 사용
  • 5. 제네릭 타입 제한 (Bounded Type)
  • 상위 클래스 제한
  • 제네릭 타입 제한 사용
  • 6. 와일드카드 (?)
  • 와일드카드 사용 예시
  • 7. 제네릭의 제한점
  • 8. 제네릭의 장점
  • 정리
  1. 자바

09 클래스와 자료형

Object 클래스

Object 클래스는 자바에서 모든 클래스의 최상위 부모 클래스입니다. 즉, 자바의 모든 클래스는 암시적으로 Object 클래스를 상속받고 있으며, 이를 통해 기본적인 동작을 모든 클래스에 제공할 수 있습니다. 자바에서 정의된 모든 클래스는 Object 클래스로부터 공통적인 메소드와 기능을 상속받아 사용하게 됩니다.

1. Object 클래스란?

  • 최상위 클래스: 자바의 모든 클래스는 Object 클래스를 상속받습니다. 이는 직접적으로 또는 간접적으로 모든 클래스가 Object 클래스의 서브클래스가 된다는 의미입니다.

  • 기본 제공 메소드: Object 클래스는 모든 객체가 사용할 수 있는 기본 메소드를 제공하며, 이 메소드들은 객체의 기본적인 동작(비교, 출력, 해시코드 등)을 정의합니다.

Object 클래스의 주요 메소드

1. equals(Object obj)

edu.ch9.objectClassMethod.equals 패키지

  • 객체의 동등성을 비교하는 메소드입니다. 기본적으로는 참조 값(메모리 주소)을 비교하지만, 개발자가 이 메소드를 오버라이드하여 객체의 상태 값을 기준으로 비교할 수 있습니다.

public class Person {
    String name;

    Person(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return this.name.equals(person.name);
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");
        System.out.println(p1.equals(p2));  // 출력: true
    }
}
  • 위 코드에서 equals() 메소드를 오버라이드하여 객체의 name 필드를 기준으로 동등성을 비교했습니다.

2. hashCode()

  • 객체의 해시코드 값을 반환(각 인스턴스 고유의 메모리 위치값을 정수로 반환)하는 메소드로, 동등한 객체는 동일한 해시코드를 반환해야 합니다.

  • hashCode()와 equals()는 함께 오버라이드하는 것이 일반적입니다. 특히 HashMap이나 HashSet과 같은 컬렉션에서 객체를 저장하거나 검색할 때 hashCode()가 사용됩니다.

@Override
public int hashCode() {
    return Objects.hash(name);  // name 필드를 기준으로 해시코드 반환
}

3. toString()

edu.ch9.objectClassMethod.toString 패키지

  • 기본적으로는 클래스명과 해시값을 반환하는 메소드입니다.

  • println 메소드로 객체 출력시 기본적으로 이 메소드의 결과값 출력

  • 객체의 문자열 표현을 반환하는 메소드지만 이를 오버라이드하여 객체의 유의미한 정보를 반환하도록 커스터마이징할 수 있습니다.

public class Person {
    String name;

    Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person[name=" + name + "]";
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Alice");
        System.out.println(p1);  // 출력: Person[name=Alice]
    }
}
  • 위의 예시에서는 toString()을 오버라이드하여 객체의 의미 있는 정보를 출력하도록 했습니다.

Wrapper 클래스

Wrapper 클래스는 기본 자료형(Primitive types)을 객체로 다루기 위해 제공되는 자바의 클래스입니다. 자바에는 8가지 기본 자료형이 있으며, 이 기본 자료형들은 객체가 아니기 때문에 메소드 호출이나 컬렉션 프레임워크와 같은 곳에서 직접 사용할 수 없습니다. 이러한 문제를 해결하기 위해 Wrapper 클래스가 도입되었습니다.

1. Wrapper 클래스란?

  • Wrapper 클래스는 기본 자료형을 객체로 감싸는 클래스입니다.

  • 기본 자료형을 객체로 다룰 수 있도록 도와줍니다.

  • 자바의 컬렉션 클래스(ArrayList, HashMap 등)과 같은 클래스들은 객체만 다룰 수 있으므로, 기본 자료형을 객체로 변환해야 할 때 Wrapper 클래스를 사용합니다.

2. 기본 자료형과 대응되는 Wrapper 클래스

자바에서는 각 기본 자료형에 대응되는 Wrapper 클래스가 존재합니다. 다음은 기본 자료형과 그에 대응하는 Wrapper 클래스입니다.

기본 자료형

Wrapper 클래스

byte

Byte

short

Short

int

Integer

long

Long

float

Float

double

Double

char

Character

boolean

Boolean

3. Wrapper 클래스의 사용 예시

박싱(Boxing)

  • 기본 자료형을 Wrapper 객체로 변환하는 과정입니다.

  • 예를 들어, int를 Integer 객체로 변환하는 것이 박싱입니다.

int num = 100;
Integer boxedNum = Integer.valueOf(num);  // 박싱

언박싱(Unboxing)

  • Wrapper 객체를 기본 자료형으로 변환하는 과정입니다.

  • 예를 들어, Integer 객체를 int로 변환하는 것이 언박싱입니다.

Integer wrapperInt = Integer.valueOf(200);
int num = wrapperInt.intValue();  // 언박싱

기본 자료형을 객체로 변환

Wrapper 클래스를 사용하여 기본 자료형을 객체로 변환할 수 있습니다.

edu.ch9.wrapper 패키지

public class WrapperExample {
    public static void main(String[] args) {
        // 기본 자료형
        int primitiveInt = 5;

        // 기본 자료형을 Wrapper 객체로 변환 (박싱)
        Integer wrapperInt = Integer.valueOf(primitiveInt);

        // Wrapper 객체를 기본 자료형으로 변환 (언박싱)
        int unboxedInt = wrapperInt.intValue();

        System.out.println("Wrapper 객체: " 
	        + wrapperInt);  // 출력: Wrapper 객체: 5
        System.out.println("언박싱된 값: " 
	        + unboxedInt);  // 출력: 언박싱된 값: 5
    }
}

4. 오토박싱과 오토언박싱

오토박싱(auto-boxing)과 오토언박싱(auto-unboxing)을 통해 기본 자료형과 Wrapper 클래스 간의 변환이 자동으로 이루어집니다. 이로 인해 개발자는 명시적으로 valueOf()나 intValue() 같은 메소드를 호출하지 않아도 됩니다.

오토박싱: 기본 자료형을 자동으로 Wrapper 객체로 변환하는 과정.

edu.ch9.wrapper 패키지

public class AutoBoxingExample {
    public static void main(String[] args) {
        // 오토박싱: 기본 자료형이 자동으로 Wrapper 객체로 변환
        Integer wrapperInt = 10;  // 자동으로 Integer.valueOf(10)을 호출한 것과 같음
        System.out.println("Wrapper 객체: " 
	        + wrapperInt);  // 출력: Wrapper 객체: 10
    }
}

오토언박싱: Wrapper 객체를 자동으로 기본 자료형으로 변환하는 과정.

edu.ch9.wrapper 패키지

public class AutoUnboxingExample {
    public static void main(String[] args) {
        Integer wrapperInt = 20;

        // 오토언박싱: Wrapper 객체가 자동으로 기본 자료형으로 변환
        int primitiveInt = wrapperInt;  // 자동으로 wrapperInt.intValue()를 호출한 것과 같음
        System.out.println("언박싱된 값: " + primitiveInt);  // 출력: 언박싱된 값: 20
    }
}

혼용해서 계산 가능

        int primSum = primInt + wrapperInt;
        Integer wrapSum = primInt + wrapperInt;
        System.out.println(primSum);
        System.out.println(wrapSum);

5. Wrapper 클래스의 주요 메소드

Wrapper 클래스는 다양한 메소드를 제공합니다. 몇 가지 중요한 메소드를 살펴보겠습니다.

  • parseOOO(String): 문자열을 기본 자료형으로 변환합니다.

int num = Integer.parseInt("123");
double d = Double.parseDouble("3.14");
  • .valueOf(String): 문자열을 해당 Wrapper 객체로 변환합니다.

    Integer intObj = Integer.valueOf("123");
    Double doubleObj = Double.valueOf("3.14");
  • OOOValue(): Wrapper 객체의 값을 해당 기본 자료형으로 변환합니다.

    int intVal = intObj.intValue();
    double doubleVal = doubleObj.doubleValue();

6. Wrapper 클래스의 활용 예시

1. 컬렉션 클래스와의 사용

Wrapper 클래스를 사용하면 기본 자료형을 컬렉션 클래스와 함께 사용할 수 있습니다. 기본 자료형은 컬렉션에 직접 넣을 수 없기 때문에, Wrapper 클래스가 필요합니다.

edu.ch9.wrapper 패키지

import java.util.ArrayList;

public class CollectionExample {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();

        // 오토박싱: 기본 자료형을 컬렉션에 추가
        list.add(10);
        list.add(20);

        // 오토언박싱: 컬렉션에서 꺼낸 값을 기본 자료형으로 변환
        int firstValue = list.get(0);
        System.out.println("첫 번째 값: " + firstValue);  // 출력: 첫 번째 값: 10
    }
}

2. 상수로서의 사용

Wrapper 클래스는 각 자료형의 최대값과 최소값 같은 상수를 제공합니다.

edu.ch9.wrapper 패키지

public class WrapperConstantsExample {
    public static void main(String[] args) {
        System.out.println("int의 최대값: " 
	        + Integer.MAX_VALUE);  // 출력: int의 최대값: 2147483647
        System.out.println("int의 최소값: " 
	        + Integer.MIN_VALUE);  // 출력: int의 최소값: -2147483648
    }
}

정리

  • Wrapper 클래스는 기본 자료형을 객체로 다루기 위해 제공되는 클래스입니다.

  • 각 기본 자료형(int, double, boolean 등)에 대응하는 Wrapper 클래스가 있습니다.

  • 박싱은 기본 자료형을 객체로 변환하는 과정이고, 언박싱은 Wrapper 객체를 기본 자료형으로 변환하는 과정입니다.

  • 자바 5 이후에는 오토박싱과 오토언박싱 기능을 통해 기본 자료형과 Wrapper 객체 간의 변환이 자동으로 이루어집니다.

제네릭

제네릭(Generic)은 자바에서 데이터의 타입을 일반화할 수 있는 기능입니다. 제네릭을 사용하면 클래스, 인터페이스, 메소드를 정의할 때 특정 데이터 타입에 의존하지 않고 여러 데이터 타입을 다룰 수 있게 됩니다. 이는 컴파일 시 타입 체크를 가능하게 하여 타입 안정성을 높이고, 형 변환(casting)의 필요성을 줄여 코드의 안전성과 가독성을 향상시킵니다.

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

  • 타입 안정성: 컴파일 시에 데이터 타입을 체크하기 때문에, 실행 중에 발생할 수 있는 ClassCastException을 방지할 수 있습니다.

  • 코드 재사용성: 다양한 타입을 다루는 재사용 가능한 클래스와 메소드를 만들 수 있습니다.

  • 가독성: 코드에서 데이터 타입이 명확히 드러나므로 읽기 쉽고 이해하기 쉬운 코드를 작성할 수 있습니다.

2. 제네릭의 기본 문법

제네릭 타입을 사용할 때는 타입 파라미터를 사용합니다. 가장 흔히 쓰는 타입 파라미터는 <T>로, 이는 임의의 타입을 의미합니다. 자주 사용되는 타입 파라미터는 다음과 같습니다.

  • T: Type (자료형)

  • E: Element (컬렉션의 원소)

  • K: Key (키)

  • V: Value (값)

  • N: Number (숫자)

3. 제네릭 클래스

제네릭 클래스 정의

제네릭 클래스를 정의할 때는 클래스 이름 뒤에 <T>와 같은 타입 파라미터를 추가합니다.

edu.ch9.generic 패키지

public class Box<T> {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}
  • 이 예제에서 <T>는 임의의 타입을 나타내며, 이 클래스를 사용할 때 어떤 타입을 사용할지 지정할 수 있습니다.

제네릭 클래스 사용

edu.ch9.generic 패키지

public class Main {
    public static void main(String[] args) {
        // 제네릭 타입을 Integer로 지정
        Box<Integer> integerBox = new Box<>();
        integerBox.setItem(123);
        System.out.println("Box의 내용: " + integerBox.getItem());  // 출력: Box의 내용: 123

        // 제네릭 타입을 String으로 지정
        Box<String> stringBox = new Box<>();
        stringBox.setItem("Hello");
        System.out.println("Box의 내용: " + stringBox.getItem());  // 출력: Box의 내용: Hello
    }
}
  • Box<Integer>와 Box<String>은 제네릭을 통해 다양한 타입을 수용할 수 있게 됩니다.

  • 컴파일 시에 타입이 체크되므로 타입 안정성이 보장됩니다.

4. 제네릭 메소드

제네릭 메소드는 메소드의 리턴 타입 앞에 타입 파라미터를 추가하여 정의합니다. 이렇게 하면 메소드에서 사용되는 매개변수나 리턴 타입을 제네릭으로 지정할 수 있습니다.

제네릭 메소드 정의

제네릭 메소드 간단한 예제

    public static <T> T genericTest(T a, T b) {
        // 두 값을 출력한 뒤 첫 번째 값을 반환
        System.out.println("첫 번째 값: " + a);
        System.out.println("두 번째 값: " + b);
        return a;
    }

    public static void main(String[] args) {
        // 문자열 타입
        String result1 = genericTest("Hello", "World");
        System.out.println("반환된 값: " + result1);

        // 정수 타입
        Integer result2 = genericTest(10, 20);
        System.out.println("반환된 값: " + result2);

        // 실수 타입
        Double result3 = genericTest(3.14, 2.71);
        System.out.println("반환된 값: " + result3);
    }

edu.ch9.generic 패키지

public class Util {
    // 제네릭 메소드
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.print(element + " ");
        }
        System.out.println();
    }
}

제네릭 메소드 사용

edu.ch9.generic 패키지

public class Main {
    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3, 4, 5};
        String[] strArray = {"A", "B", "C"};

        // 제네릭 메소드 호출
        Util.printArray(intArray);  // 출력: 1 2 3 4 5
        Util.printArray(strArray);  // 출력: A B C
    }
}
  • <T>는 메소드가 호출될 때 타입을 지정할 수 있도록 해주며, 이로써 메소드가 다양한 타입을 수용할 수 있습니다.

5. 제네릭 타입 제한 (Bounded Type)

때로는 제네릭 타입에 특정 상위 클래스나 인터페이스를 상속받는 타입만 허용하고 싶을 때가 있습니다. 이럴 때 제네릭 타입 제한을 사용할 수 있습니다.

상위 클래스 제한

edu.ch9.generic 패키지

// Number를 상속하는 타입만 허용
public class Calculator<T extends Number> {
    public double add(T num1, T num2) {
        return num1.doubleValue() + num2.doubleValue();
    }
}

제네릭 타입 제한 사용

edu.ch9.generic 패키지

public class Main {
    public static void main(String[] args) {
        Calculator<Integer> intCalculator = new Calculator<>();
        System.out.println("합계: "
                + intCalculator.add(10, 20));  // 출력: 합계: 30.0

        Calculator<Double> doubleCalculator = new Calculator<>();
        System.out.println("합계: "
                + doubleCalculator.add(5.5, 3.2));  // 출력: 합계: 8.7

        // Calculator<String> stringCalculator = new Calculator<>();
        // 오류: String은 Number를 상속하지 않음
    }
}
  • <T extends Number>는 Number를 상속받는 타입만 T로 사용할 수 있도록 제한합니다.

  • 이렇게 하면 제네릭 클래스나 메소드에서 특정 타입 계층구조만 수용할 수 있도록 제한할 수 있습니다.

제네릭 타입 제한 추가 예제

interface Shape {
    double getArea();
}

class Circle implements Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

class Rectangle implements Shape {
    private double width, height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double getArea() {
        return width * height;
    }
}

public class ShapePrinter<T extends Shape> {

    public void printArea(T shape) {
        System.out.println("Shape area: " + shape.getArea());
    }

    public static void main(String[] args) {
        ShapePrinter<Circle> circlePrinter = new ShapePrinter<>();
        circlePrinter.printArea(new Circle(5)); // 출력: Shape area: 78.53981633974483

        ShapePrinter<Rectangle> rectanglePrinter = new ShapePrinter<>();
        rectanglePrinter.printArea(new Rectangle(4, 5)); // 출력: Shape area: 20.0
    }
}

  • 특정 인터페이스를 구현한 클래스 만으로 타입을 허용하도록 제한할 수 있습니다.

6. 와일드카드 (?)

  • 와일드카드(?)는 제네릭 타입을 **유연하게 사용(다형성)**하기 위해 사용됩니다.

  • 제한 없는 와일드카드 (?)

    • 모든 타입을 허용

  • 상한 제한 와일드카드 (? extends Type)

    • 특정 클래스의 하위 타입만 허용

  • 하한 제한 와일드카드 (? super Type)

    • 특정 클래스의 상위 타입만 허용

와일드카드 사용 예시

제한 없는 와일드카드 : edu.ch9.generic 패키지

import java.util.ArrayList;
import java.util.List;

public class WildcardExample {
    // 모든 타입의 리스트를 출력 (와일드카드 사용)
    public static void printList(List<?> list) {
        for (Object element : list) {
            System.out.print(element + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        intList.add(1);
        intList.add(2);
        intList.add(3);

        List<String> strList = new ArrayList<>();
        strList.add("A");
        strList.add("B");
        strList.add("C");

        // 와일드카드를 사용하여 어떤 타입의 리스트든 전달 가능
        printList(intList);  // 출력: 1 2 3
        printList(strList);  // 출력: A B C
    }
}

상한 제한 와일드카드 (? extends Type)

import java.util.List;

public class WildcardExample {

    // 상한 제한 와일드카드: Number 또는 그 하위 클래스만 허용
    public static double calculateSum(List<? extends Number> list) {
        double sum = 0;
        for (Number number : list) {
            sum += number.doubleValue(); // Number의 doubleValue() 메서드 사용 가능
        }
        return sum;
    }

    public static void main(String[] args) {
        List<Integer> intList = List.of(1, 2, 3, 4, 5);
        List<Double> doubleList = List.of(1.1, 2.2, 3.3);

        System.out.println("정수 리스트 합계: " + calculateSum(intList)); // 출력: 15.0
        System.out.println("실수 리스트 합계: " + calculateSum(doubleList)); // 출력: 6.6
    }
}

하한 제한 와일드카드 (? super Type)

import java.util.List;
import java.util.ArrayList;

public class WildcardExample {

    // 하한 제한 와일드카드: Integer 또는 그 상위 클래스만 허용
    public static void addNumbers(List<? super Integer> list) {
        list.add(10); // Integer 타입 추가 가능
        list.add(20);
    }

    public static void main(String[] args) {
        List<Number> numberList = new ArrayList<>();
        List<Object> objectList = new ArrayList<>();

        addNumbers(numberList);
        addNumbers(objectList);

        System.out.println("Number 리스트: " + numberList); // 출력: [10, 20]
        System.out.println("Object 리스트: " + objectList); // 출력: [10, 20]
    }
}

7. 제네릭의 제한점

  • 기본 자료형 사용 불가: 제네릭에서는 기본 자료형(int, double 등)을 직접 사용할 수 없습니다. 대신, Wrapper 클래스(Integer, Double 등)를 사용해야 합니다.

  • 런타임 시 타입 정보 소실: 제네릭은 컴파일 시에만 타입을 체크하며, 런타임 시에는 타입 정보가 제거되는 타입 소거(type erasure)가 일어납니다. 따라서 런타임에는 제네릭 타입에 대한 정확한 타입 정보를 알 수 없습니다.

8. 제네릭의 장점

  • 타입 안정성: 컴파일 시에 데이터 타입을 체크하여, 런타임 오류를 방지할 수 있습니다.

  • 코드 재사용성: 다양한 데이터 타입을 처리하는 재사용 가능한 클래스 및 메소드를 작성할 수 있습니다.

  • 형 변환의 필요성 감소: 제네릭을 사용하면 명시적 형 변환이 필요하지 않아, 코드가 더 깔끔하고 에러가 줄어듭니다.

정리

제네릭은 자바에서 타입 안정성을 유지하면서 유연하고 재사용 가능한 코드를 작성하는 데 필수적인 기능입니다. 이를 통해 여러 타입의 객체를 하나의 클래스나 메소드로 처리할 수 있으며, 컴파일 시 타입 체크를 통해 안전한 코드를 작성할 수 있습니다.

Previous열거형 ENUM 보충자료Next다형성 보충자료

Last updated 5 months ago