Java에서 일반 배열 생성 오류 해결
이 자습서는 코드 샘플을 통해 일반 배열 생성
오류를 설명하고 일반 배열을 만드는 동안 이 오류가 발생하는 이유를 강조합니다. 이 토론은 Object
배열 및 reflect
기능을 사용하여 일반 배열을 만드는 방법을 배우는 솔루션으로 이어집니다.
Java의 일반 배열 생성
오류 데모
예제 코드(DemoGenArray.java
클래스):
import java.util.Arrays;
public class DemoGenArray<T> {
private T[] genericArray;
DemoGenArray(int size) {
genericArray = new T[size]; //<----This Line Has Generic Array Creation Error
}
public T get(int index) {
return (T) genericArray[index];
}
public void set(int index, T item) {
genericArray[index] = item;
}
@Override
public String toString() {
return Arrays.toString(genericArray);
}
}
이 클래스에서는 지정된 배열 크기
를 사용하여 일반 배열을 만들고 초기화하려고 합니다. 또한 배열에 요소를 추가하고 주어진 인덱스
에서 항목을 개별적으로 반환합니다.
toString()
은 전체 배열을 한 번에 반환합니다.
문제는 생성자에서 가리키는 줄에 일반 배열 생성
오류가 있다는 것입니다. 해결책을 찾는 데 도움이 될 이 오류의 가능한 원인을 살펴보겠습니다.
Java에서 일반 배열 생성
오류의 가능한 원인
Java에서는 불가능한 코드에서 일반 배열을 만들려고 합니다. Java가 이러한 구문이 작동하지 않도록 명시적으로 중지하기로 의식적으로 결정하기 때문입니다.
배열은 Java에서 공변량(상위 유형 참조에 하위 유형을 할당할 수 있음)인 반면 제네릭은 그렇지 않음을 기억하십시오.
private T[] genericArray;
genericArray = new T[size];
위 두 줄의 코드는 아래 주어진 것과 동일합니다. 당신은 그들 중 하나를 사용할 수 있습니다.
private T[] genericArray = new T[size];
Java가 구현하는 유형 삭제
로 인해 발생합니다. Java 컴파일러에 의해 수행되는 프로세스입니다.
제네릭에서 매개변수화된 유형을 제거하고 바이트 코드의 원시 유형에 매핑합니다.
바이트 코드에는 제네릭에 대한 세부 정보가 없습니다. T
유형을 사용하면 컴파일 타임에는 문제가 없지만 런타임에는 의미가 없습니다.
다른 방법으로 코드 예제와 함께 아래에 제공된 이 제한을 우회할 수 있습니다. 아래에서 각각 알아봅시다.
Java에서 일반 배열 생성
오류를 근절하기 위한 가능한 솔루션
이미 알고 있듯이 컴파일러는 런타임에 매개변수화된 유형에 대한 정보를 가지고 있지 않습니다. 따라서 제네릭을 사용해야 할 때마다 배열을 사용하는 대신 Java 컬렉션
프레임워크의 목록 구성 요소를 선호하고 사용하는 것이 좋습니다.
그러나 우리는 여전히 배열과 같은 일반 구조를 만들 수 있지만 이 솔루션은 선택됨
또는 선택되지 않음
여부에 따라 달라집니다. 체크되지 않은
경우 객체
배열을 사용합니다.
checked
의 경우 Java의 reflect
기능을 사용할 수 있습니다. 각각이 어떻게 작동하는지 봅시다.
해결 방법 1: 객체
배열 사용
예제 코드(DemoGenArray.java
클래스):
import java.util.Arrays;
public class DemoGenArray<T> {
private Object[] genericArray;
DemoGenArray(int size) {
genericArray = new Object[size];
}
public T get(int index) {
return (T) genericArray[index];
}
public void set(int index, T item) {
genericArray[index] = item;
}
@Override
public String toString() {
return Arrays.toString(genericArray);
}
}
예제 코드(GenArray.java
클래스):
public class GenArray {
public static void main(String[] args) {
DemoGenArray<String> strArray = new DemoGenArray(3);
strArray.set(0, "one");
strArray.set(1, "two");
strArray.set(2, "three");
DemoGenArray<Integer> intArray = new DemoGenArray(3);
intArray.set(0, 10);
intArray.set(1, 20);
intArray.set(2, 30);
DemoGenArray<Double> doubleArray = new DemoGenArray(3);
doubleArray.set(0, 15.0);
doubleArray.set(1, 110.0);
doubleArray.set(2, 10.0);
System.out.println("Integer Array: " + intArray);
System.out.println("String Array: " + strArray);
System.out.println("Double Array: " + doubleArray);
}
}
출력:
Integer Array: [10, 20, 30]
String Array: [one, two, three]
Double Array: [15.0, 110.0, 10.0]
여기에서는 DemoGenArray
클래스가 확인되지 않음
(약한 타이핑)이기 때문에 일반 배열을 시뮬레이트하기 위해 Object
배열을 사용합니다. 인수로 전달된 객체에 대해 유형 검사가 수행되지 않는다는 것을 알고 있는 경우 이 접근 방식을 사용할 수 있습니다.
또한 일반적인 get()
및 set()
메서드를 사용하여 각각 값을 반환하고 값을 설정합니다. get()
메서드는 T
에 대한 명시적 캐스트를 사용합니다. 여기서 T
는 제네릭에 대한 자리 표시자처럼 작동하고 모든 값/요소를 나타냅니다.
이것은 set()
및 get()
메서드를 사용하고 사용자가 Object
배열에 직접 액세스하지 못하게 하면 잘 작동합니다. main()
메서드를 포함하는 GenArray
클래스로 이동합니다.
여기에서 DemoGenArray
클래스의 인스턴스를 생성합니다.
DemoGenArray
클래스를 인스턴스화하고 채우는 동안 필요한 유형을 전달합니다. 그런 다음 toString()
메서드를 사용하여 모든 인스턴스의 내용을 작성합니다.
해결책 2: 반사
기능 사용
예제 코드(DemoGenArray.java
클래스):
import java.lang.reflect.Array;
import java.util.Arrays;
public class DemoGenArray<T> {
private T[] genericArray;
DemoGenArray(Class<T> classType, int size) {
genericArray = (T[]) Array.newInstance(classType, size);
}
public T get(int index) {
return (T) genericArray[index];
}
public void set(int index, T item) {
genericArray[index] = item;
}
@Override
public String toString() {
return Arrays.toString(genericArray);
}
}
예제 코드(GenArray.java
클래스):
public class GenArray {
public static void main(String[] args) {
DemoGenArray<String> strArray = new DemoGenArray(String.class, 3);
strArray.set(0, "one");
strArray.set(1, "two");
strArray.set(2, "three");
DemoGenArray<Integer> intArray = new DemoGenArray(Integer.class, 3);
intArray.set(0, 10);
intArray.set(1, 20);
intArray.set(2, 30);
DemoGenArray<Double> doubleArray = new DemoGenArray(Double.class, 3);
doubleArray.set(0, 15.0);
doubleArray.set(1, 110.0);
doubleArray.set(2, 10.0);
System.out.println("Integer Array: " + intArray);
System.out.println("String Array: " + strArray);
System.out.println("Double Array: " + doubleArray);
}
}
출력:
Integer Array: [10, 20, 30]
String Array: [one, two, three]
Double Array: [15.0, 110.0, 10.0]
여기에서는 유형이 런타임에만 알려진 일반 배열을 만들기 위해 리플렉션 클래스를 사용하고 있습니다. 이 솔루션은 DemoGenArray
클래스의 두 가지 차이점을 제외하면 솔루션 1과 유사합니다.
먼저 DemoGenArray
클래스에 배열의 유형과 크기라는 두 가지 인수를 받는 생성자가 있습니다. 둘째, Array.newInstance()
메서드를 사용하여 genericArray
를 초기화합니다.
Array.newInstance()
메서드는 주어진 차원(배열의 크기) 및 구성 요소 유형을 사용하여 새 배열을 만듭니다.