본문 바로가기
Everyday Study

2024.07.17 (수) { raw type, Arrays.asList, 자바에 2가지의 경고 "unchecked", "varargs" }

by xogns93 2024. 7. 17.

raw type 

Raw type은 Java의 제네릭스(Generic)를 사용할 때 타입 파라미터를 명시하지 않은 경우를 의미합니다. 간단히 말해, 제네릭 클래스나 인터페이스를 사용할 때 타입을 지정하지 않고 사용하는 것을 raw type이라고 합니다. 이는 Java 5 이전의 호환성을 위해 제공되며, 제네릭스가 도입되기 이전의 코드와 호환성을 유지하기 위해 존재합니다.

 

Raw Type의 문제점

raw type을 사용하면 다음과 같은 문제가 발생할 수 있습니다:

  1. 타입 안전성 손실: 컴파일러가 타입을 체크하지 않기 때문에 잘못된 타입의 객체가 저장될 수 있습니다. 이는 런타임 오류를 발생시킬 수 있습니다.
  2. 가독성 저하: 코드를 읽는 사람이 타입 정보를 알 수 없기 때문에 코드의 가독성이 떨어집니다.
  3. 경고 발생: 컴파일 시에 unchecked operation 경고가 발생합니다.

제너릭클래스 뒤에 <> 

제너릭메서드 타입파라미터 위치에 <>

Box<T>에서 T가 타입 변수


 

일반(정규)클래스가 제너릭클래스를 상속하려면 파라미터가 ‘파라미터화’된 클래스여야한다 되어야 한다!!! 

제네릭 클래스 정의: Box<T> 클래스는 제네릭 타입 T를 받아들입니다. 이는 어떤 타입이든 Box 클래스로 감쌀 수 있음을 의미합니다.

public class Box<T> {
    private T content;

    public Box(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }

    public void setContent(T content) {
        this.content = content;
    }
}

 

일반 클래스에서 제네릭 클래스 상속: StringBox 클래스는 Box<String>을 상속받습니다. 여기서 Box<String>은 Box 클래스의 제네릭 타입 T를 String으로 구체화한 형태입니다.

public class StringBox extends Box<String> {
    public StringBox(String content) {
        super(content);
    }

    public void printContent() {
        System.out.println("Content: " + getContent());
    }

    public static void main(String[] args) {
        StringBox stringBox = new StringBox("Hello, World!");
        stringBox.printContent(); // 출력: Content: Hello, World!
    }
}

이 예제에서 StringBox는 Box<String>을 상속하여 Box 클래스의 모든 기능을 String 타입으로 사용할 수 있습니다. 이는 일반 클래스가 제네릭 클래스를 상속할 때 타입 파라미터를 구체적인 타입으로 지정하는 일반적인 방법을 보여줍니다.


 

와일드카드는 타입 파라미터가 아니며, 제네릭을 사용할 때 타입을 유연하게 다루기 위한 수단입니다. 타입 파라미터는 클래스나 메소드에서 사용할 타입을 정의하는 반면, 와일드카드는 이미 정의된 제네릭 타입의 사용을 제한하거나 확장하는 데 사용됩니다.

 

인터페이스로 구체 클래스 받기 ->  Animal dog = new Dog();와 같이 인터페이스 타입으로 구체 클래스를 받습니다.

이렇게 하면 Dog 클래스의 인스턴스가 Animal 인터페이스 타입으로 취급됩니다.

 

특정 인터페이스를 구현하면 그 인터페이스 타입으로 받을 수 있다 -> Dog 클래스는 Animal 인터페이스를 구현하므로, Animal 타입으로 받을 수 있습니다. 이는 Dog가 Animal의 모든 메소드를 구현하기 때문입니다.

 

구체 클래스(Concrete Class): 구체 클래스는 모든 메소드가 구현된 클래스입니다. 인스턴스를 생성할 수 있으며, 필요한 동작을 모두 정의합니다. ,  인터페이스를 구현하는 클래스는 구체 클래스가 되며, 인터페이스의 모든 메소드를 구현해야 합니다.

// 구체 클래스
public class Dog extends Animal {
    // 추상 메소드 구현
    @Override
    public void makeSound() {
        System.out.println("Woof");
    }
}

타입 파라미터와 타입 아규먼트

타입 파라미터 (Type Parameter)

타입 파라미터는 제네릭 클래스나 인터페이스를 정의할 때 사용되는 변수와 같은 역할을 합니다. 이를 통해 다양한 타입을 처리할 수 있는 일반화된 코드를 작성할 수 있습니다. 타입 파라미터는 꺾쇠 괄호(<>) 안에 작성합니다.

타입 아규먼트 (Type Argument)

타입 아규먼트는 제네릭 클래스나 인터페이스를 사용할 때 구체적인 타입으로 지정하는 값을 말합니다. 타입 아규먼트는 타입 파라미터를 대체하는 실제 타입을 의미합니다.

 
 

제너릭인터페이스 정의

// 제네릭 인터페이스 Pair 정의
public interface Pair<K, V> {
    K getKey();
    V getValue();
}

여기서 Pair<K, V>의 <K, V>는 타입 파라미터입니다. 이는 Pair 인터페이스가 두 개의 타입 파라미터 K와 V를 사용함을 의미합니다.

 

제네릭 클래스를 구현하는 예제

// 제네릭 클래스 OrderedPair 정의 및 Pair 인터페이스 구현
public class OrderedPair<K, V> implements Pair<K, V> {
    private K key;
    private V value;

    public OrderedPair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public K getKey() {
        return key;
    }

    @Override
    public V getValue() {
        return value;
    }

    public static void main(String[] args) {
        // OrderedPair 인스턴스를 생성할 때 타입 아규먼트 제공
        OrderedPair<String, Integer> pair = new OrderedPair<>("Age", 30);
        System.out.println("Key: " + pair.getKey() + ", Value: " + pair.getValue());
    }
}

여기서 OrderedPair<K, V>의 <K, V>는 타입 파라미터입니다. 이는 OrderedPair 클래스가 두 개의 타입 파라미터 K와 V를 사용함을 의미합니다.

OrderedPair가 Pair<K, V>를 구현할 때, 뒤에 나오는 <K, V>는 타입 아규먼트입니다. 이는 OrderedPair 클래스가 Pair 인터페이스의 타입 파라미터를 동일한 타입 파라미터로 사용한다는 것을 의미합니다.

 

인스턴스 생성

OrderedPair<String, Integer> pair = new OrderedPair<>("Age", 30);

여기서 OrderedPair<String, Integer>의 <String, Integer>는 타입 아규먼트입니다. 이는 OrderedPair 클래스의 타입 파라미터 K와 V가 각각 String과 Integer로 대체됨을 의미합니다.

 

요약

  1. 타입 파라미터 (Type Parameter):
    • 제네릭 클래스나 인터페이스를 정의할 때 사용되는 변수.
    • 예: public class OrderedPair<K, V> { ... }
  2. 타입 아규먼트 (Type Argument):
    • 제네릭 클래스를 사용할 때 실제로 지정하는 구체적인 타입.
    • 예: OrderedPair<String, Integer> pair = new OrderedPair<>("Age", 30);

Arrays.asList

Arrays.asList 메소드는 Java에서 배열을 고정 크기의 리스트로 변환하는 유틸리티 메소드입니다. 이 메소드는 java.util.Arrays 클래스에 정의되어 있으며, 배열을 리스트로 쉽게 변환할 수 있도록 도와줍니다.

 

import java.util.Arrays;
import java.util.List;

public class ArraysAsListExample {
    public static void main(String[] args) {
        // 문자열 배열을 리스트로 변환
        String[] stringArray = {"Apple", "Banana", "Cherry"};
        List<String> stringList = Arrays.asList(stringArray);
        
        // 리스트 출력
        System.out.println(stringList); // 출력: [Apple, Banana, Cherry]
        
        // 정수 배열을 리스트로 변환
        Integer[] intArray = {1, 2, 3, 4, 5};
        List<Integer> intList = Arrays.asList(intArray);
        
        // 리스트 출력
        System.out.println(intList); // 출력: [1, 2, 3, 4, 5]
    }
}

 

  • Arrays.asList는 배열을 고정 크기의 리스트로 변환합니다.
  • 반환된 리스트는 원본 배열에 대한 뷰(view)이며, 리스트의 요소를 변경하면 원본 배열도 변경됩니다.
  • 리스트의 크기를 변경할 수 없으며, 요소를 추가하거나 제거하려고 하면 UnsupportedOperationException이 발생합니다.
  • 기본 타입 배열을 사용할 경우 주의가 필요하며, 래퍼 클래스 배열을 사용하는 것이 좋습니다.

 


자바에 2가지의 경고가 있음  "unchecked",    "varargs"

 

1. Unchecked 경고

원인

"unchecked" 경고는 제네릭 타입의 사용에서 컴파일러가 타입 안전성을 보장할 수 없는 상황에서 발생합니다. 주로 제네릭과 관련된 형변환 시 나타납니다.

 

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

public class UncheckedWarningExample {
    public static void main(String[] args) {
        List rawList = new ArrayList(); // raw 타입 사용
        rawList.add("Hello");
        rawList.add(10);

        List<String> stringList = rawList; // unchecked 경고 발생
        for (String s : stringList) {
            System.out.println(s);
        }
    }
}

 

해결 방법

제네릭 타입을 명시적으로 지정하여 경고를 제거할 수 있습니다.

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

public class UncheckedWarningFixed {
    public static void main(String[] args) {
        List<String> rawList = new ArrayList<>(); // 제네릭 타입 명시
        rawList.add("Hello");
        // rawList.add(10); // 컴파일 오류 발생

        List<String> stringList = rawList; // 경고 없음
        for (String s : stringList) {
            System.out.println(s);
        }
    }
}

 

 

2. Varargs 경고

원인

"varargs" 경고는 제네릭 타입의 가변 인자를 사용할 때 발생합니다. 이는 타입 안전성을 보장할 수 없기 때문에 발생합니다.

 

import java.util.Arrays;
import java.util.List;

public class VarargsWarningExample {
    public static void faultyMethod(List<String>... lists) {
        Object[] array = lists;
        array[0] = Arrays.asList(42); // 경고 발생
        String s = lists[0].get(0);   // ClassCastException 발생 가능
    }

    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("Hello");
        List<String> list2 = Arrays.asList("World");
        faultyMethod(list1, list2);
    }
}

해결 방법

가변 인자를 사용하지 않고, 리스트를 명시적으로 전달하는 방법으로 해결할 수 있습니다.

import java.util.Arrays;
import java.util.List;

public class VarargsWarningFixed {
    public static void safeMethod(List<List<String>> lists) {
        for (List<String> list : lists) {
            for (String s : list) {
                System.out.println(s);
            }
        }
    }

    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("Hello");
        List<String> list2 = Arrays.asList("World");
        List<List<String>> listOfLists = Arrays.asList(list1, list2);
        safeMethod(listOfLists);
    }
}

요약

  1. Unchecked 경고:
    • 원인: 제네릭 타입을 명시하지 않은 경우 발생.
    • 해결: 제네릭 타입을 명시적으로 지정.
  2. Varargs 경고:
    • 원인: 제네릭 타입의 가변 인자를 사용할 때 발생.
    • 해결: 가변 인자 대신 리스트를 명시적으로 전달.

 


와일드카드 타입

  • extends 와일드카드 (<? extends Type>): 주로 데이터를 제공하는(in) 매개변수에 사용됩니다.
  • super 와일드카드 (<? super Type>): 주로 데이터를 소비하는(out) 매개변수에 사용됩니다.

"In" 변수

"In" 변수는 데이터를 제공하는 역할을 합니다. 예를 들어, 데이터를 복사하는 메소드의 소스 매개변수는 데이터를 제공하므로 "in" 변수입니다. 이런 경우 extends 와일드카드를 사용합니다.

"Out" 변수

"Out" 변수는 데이터를 소비하는 역할을 합니다. 예를 들어, 데이터를 복사하는 메소드의 대상 매개변수는 데이터를 받으므로 "out" 변수입니다. 이런 경우 super 와일드카드를 사용합니다.

 

요약

  • In 변수: 데이터를 제공하는 매개변수로, <? extends Type> 와일드카드를 사용합니다.
  • Out 변수: 데이터를 소비하는 매개변수로, <? super Type> 와일드카드를 사용합니다.
  • extends 와일드카드는 읽기 전용이며, super 와일드카드는 쓰기 전용으로 생각할 수 있습니다.