본문 바로가기
Spring

[4] 자바 중급 문법 - Generic

by 민지기il 2025. 3. 26.

[1] 제네릭 적용

1) 선언

// string 타입
public class StringBox {
    private String value;
    public void set(String object) {
        this.value = object;
}
    public String get() {
        return value;
} }

//int 타입
public class IntegerBox {
	private Integer value;
    public void set(Integer value) {
        this.value = value;
}
    public Integer get() {
        return value;
} }

2) 꺼내기

public class BoxMain1 {
	public static void main(String[] args) { 
		IntegerBox integerBox = new IntegerBox(); 
        integerBox.set(10); //오토 박싱
		Integer integer = integerBox.get(); 
        System.out.println("integer = " + integer);
        StringBox stringBox = new StringBox();
        stringBox.set("hello");
        String str = stringBox.get();
        System.out.println("str = " + str);
      }
}

1) Object로 선언

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

2) 출력

public class BoxMain2 {
	public static void main(String[] args) {
		ObjectBox integerBox = new ObjectBox();
		integerBox.set(10);
		Integer integer = (Integer) integerBox.get(); //Object -> Integer 캐스팅 
        	System.out.println("integer = " + integer);
        
		ObjectBox stringBox = new ObjectBox();
		stringBox.set("hello");
		String str = (String) stringBox.get(); //Object -> String 캐스팅 
        	System.out.println("str = " + str);
		
        //잘못된 타입의 인수 전달시
		integerBox.set("문자100");
		Integer result = (Integer) integerBox.get(); 
        // String -> Integer 캐스팅 예외
        	System.out.println("result = " + str);
        }
}

 

Object를 이용해 다형성을 활용하게 됐지만 입력할 때 실수로 원하지 않는 타입이 들어갈 수 있는 타입 안전성 문제가 생긴다.

따라서 제네릭을 사용한다.

[2] 제네릭 사용

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

public class GenericMain {
    public static void main(String[] args) {
        Generic<Integer> box = new Generic<>(); //이때 T의 타입이 결정됨
        box.set(10);
        box.get();
    }
}

[3] Generic 용어

타입 매개변수: GenericBox<T> 에서 T

타입 인자: GenericBox<Integer> 에서 Integer, GenericBox<String> 에서 String

E - Element, K - Key, N - Number, T - Type, V - Value

class Data<K, V> {}  처럼 사용 가능함

 

[4] Generic 사용 예시

public class Animal {
    private String name;
    private int size;

    public Animal(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public String getName() {
        return name;
    }

    public int getSize() {
        return size;
    }
    public void sound(){
        System.out.println("울음 소리");
    }
    @Override
    public String toString(){
        return "animal: "+name+" size: "+size;
    }
}

public class Dog extends Animal{
    public Dog(String name, int size) {
        super(name, size);
    }
    @Override
    public void sound(){
        System.out.println("멍멍");
    }
}

public class Cat extends Animal{
    public Cat(String name, int size) {
        super(name, size);
    }
    @Override
    public void sound(){
        System.out.println("냐옹");
    }
}
public class Box <T>{
    private T value;
    public void set(T value){
        this.value = value;
    }
    public T get(){
        return value;
    }
}
public class AnimalMain {
    public static void main(String[] args) {
        Animal animal = new Animal("동물", 23);
        Dog dog = new Dog("멍멍이", 100);
        Cat cat = new Cat("냐옹이", 50);
        Box <Dog> dogBox = new Box<>();
        dogBox.set(dog);
        Dog findDog = dogBox.get();
        System.out.println("개 찾음: "+ findDog);

        Box <Cat> catBox = new Box<>();
        catBox.set(cat);
        Cat findCat = catBox.get();
        System.out.println("고양이 찾음: "+ findCat);
    }
}

Box를 이용해서 Dog, Cat 타입을 보관할 수 있음

 

[5] Generic2

1) 타입 매개변수 제한

: T extends Animal로 설정해서 Animal을 상속한 애들만 가능함

public class AnimalHospital<T extends Animal> {
    private T animal;
    public void set(T animal) {
        this.animal = animal;
    }
    public void checkup(){
        System.out.println(animal.getName());
        System.out.println(animal.getSize());
        animal.sound();
    }
    public T getBigger(T target){
        return animal.getSize() > target.getSize() ? animal : target;
    }
}

[6] 예시

public class GenericMethod {
    public static Object objectMethod(Object obj){
        System.out.println(obj);
        return obj;
    }
    public static <T> T genericMethod(T t){
        System.out.println(t);
        return t;
    }
    public static <T extends Number> T numberMethod(T t){
        System.out.println(t);
        return t;
    }
}

public class MethodMain {
    public static void main(String[] args) {
        Integer i = 10;
        Object object = GenericMethod.objectMethod(i);
        Integer result = GenericMethod.<Integer>genericMethod(i);
        Integer integerValue = GenericMethod.<Integer>numberMethod(10);
        Double doubleValue = GenericMethod.<Double>numberMethod(20.0);
    }
}

1) 제네릭 메서드

정의: <T> T genericMethod(T t)

타입 전달: genericMethod.<Integer>genericMethod(10)

2) static 메서드에는 T 못 씀 -> generic 메서드로 만들기

class Box<T> {
    static T staticMethod(T t) {} // 에러!
}

static <T> T staticMethod(T t) {} // 가능!

 

[7] 와일드 카드

public class WildcardEx {
    static<T> void printGenericV1(Box<T> box){
        System.out.println(box.get());
    }
    static void printWildcardV1(Box<?> box){
        System.out.println(box.get());
    }
    static <T extends Animal> void printGenericV2(Box<T> box){
        T t = box.get();
        System.out.println(t.getName());
    }
    static void printWildcardV2(Box<? extends Animal> box) { //Animal의 자식들만 받음
        Animal animal = box.get(); //Animal로 받아서 사용함
        System.out.println("이름 = " + animal.getName());
    }
    static <T extends Animal> T printAndReturnGeneric(Box<T> box) {
        T t = box.get(); // T는 Animal의 자식
        System.out.println("이름 = " + t.getName());
        return t; //T 타입을 반환
        // 1. Generic이라는 타입을 기억함
    }
    static Animal printAndReturnWildcard(Box<? extends Animal> box) {
        Animal animal = box.get(); // Animal 타입으로 받음
        System.out.println("이름 = " + animal.getName());
        return animal; // Animal 타입 반환
        // 2. Wildcard는 타입 정보 손실됨
    }
}

제네릭 메서드 <T>: 메서드에 직접 타입 매개변수를 정의함, 타입을 반환 / 변경 시에 필요

와일드 카드 <?>: 타입 정의 없이 어떤 타입이든 받음, 단순히 읽을 때만 적합

 

[8] 이레이저

1) 자바 컴파일러가 casting을 대신 해줌

예전)

List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0); // 직접 캐스팅함

제네릭)

List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0); // 컴파일러가 자동으로 캐스팅해줌

 

2) 타입 이레이저

: 자바의 제네릭은 컴파일 타임(코드 짤 때)에만 사용되고, 런타임(실행할 때)에는 제네릭 정보가 지워지는 것List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();

컴파일 타입에는 다른 타입, 실행 시점에는 둘 다 List로 처리됨

'Spring' 카테고리의 다른 글

[6] 자바 중급 문법 - List  (0) 2025.03.28
[5] 자바 중급 문법 - ArrayList  (0) 2025.03.28
[3] 자바 중급 문법 3 -- 날짜와 시간  (0) 2025.03.21
[2] 자바 중급 문법 2  (0) 2025.03.21
[1] 자바 중급 문법 1  (0) 2025.03.19