ArrayList.toArray ()의 Java 제네릭
다음과 같이 정의 된 arraylist가 있다고 가정합니다.
ArrayList<String> someData = new ArrayList<>();
나중에 코드에서 제네릭 때문에 다음과 같이 말할 수 있습니다.
String someLine = someData.get(0);
그리고 컴파일러는 문자열을 얻을 것이라는 것을 완전히 알고 있습니다. 예이 제네릭! 그러나 이것은 실패합니다.
String[] arrayOfData = someData.toArray();
toArray()
정의 된 제네릭이 아닌 항상 객체의 배열을 반환합니다. get(x)
메서드가 반환하는 내용을 알고 있지만 toArray()
기본값은 Objects 인 이유는 무엇 입니까?
당신의 구현을 보면 toArray(T[] a)
의 ArrayList를 <E> 클래스, 그것과 같다 :
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
이 방법의 문제점은 동일한 일반 유형의 배열을 전달해야한다는 것입니다. 이제이 메소드가 어떤 인수도 취하지 않는다면 구현은 다음과 유사 할 것입니다.
public <T> T[] toArray() {
T[] t = new T[size]; // compilation error
return Arrays.copyOf(elementData, size, t.getClass());
}
그러나 여기서 문제는 컴파일러가 정확히 무엇을 나타내는 지 알지 못하기 때문에 Java에서 일반 배열을 만들 수 없다는 것 T
입니다. 즉 , 수정 불가능한 유형 ( JLS §4.7 ) 의 배열 생성은 Java에서 허용되지 않습니다 .
Array Store Exception ( JLS §10.5 )의 또 다른 중요한 인용문 :
배열의 구성 요소 유형을 수정할 수없는 경우 (§4.7) Java Virtual Machine은 이전 단락에서 설명한 저장소 검사를 수행 할 수 없습니다. 이것이 수정 불가능한 요소 유형이있는 배열 생성식이 금지 된 이유입니다 (§15.10.1).
이것이 자바가 오버로드 된 버전을 제공 한 이유 toArray(T[] a)
입니다.
toArray () 메서드를 재정 의하여 E 배열을 반환 할 것임을 알립니다.
그래서 그 대신 재정의 toArray()
, 당신은 사용해야합니다 toArray(T[] a)
.
Java Doc에서 유형 매개 변수의 인스턴스를 작성할 수없는 것도 흥미로울 수 있습니다.
일반 정보는 런타임에 지워 집니다. JVM은 목록이 List<String>
또는 List<Integer>
(런타임 T
에서 List<T>
로 해석 됨 Object
) 인지 알지 못 하므로 가능한 배열 유형은 Object[]
.
toArray(T[] array)
그래도 사용할 수 있습니다 -이 경우 JVM은 주어진 배열의 클래스를 사용할 수 있으며 ArrayList
구현 에서 볼 수 있습니다 .
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
당신이 보면 에 대한 자바 독 List
인터페이스 , 당신의 두 번째 양식을 알 수 있습니다 toArray
: <T> T[] toArray(T[] a)
.
실제로 Javadoc은 원하는 작업을 정확히 수행하는 방법에 대한 예제도 제공합니다.
String[] y = x.toArray(new String[0]);
주목해야 할 점은 Java의 배열이 런타임에 구성 요소 유형을 알고 있다는 것입니다. String[]
그리고 Integer[]
런타임에 다른 클래스이며 런타임에 구성 요소 유형에 대한 배열을 요청할 수 있습니다. 따라서 런타임에 구성 요소 유형이 필요합니다 (를 new String[...]
사용하여 컴파일 타임에 수정 가능한 구성 요소 유형을 하드 코딩 하거나 Array.newInstance()
클래스 객체를 사용 및 전달하여).
반면 제네릭의 유형 인수는 런타임에 존재하지 않습니다. 간의 런타임 차이 절대적으로 없다 ArrayList<String>
하고는 ArrayList<Integer>
. 그것은 모두 단지 ArrayList
입니다.
이것이 컴포넌트 유형을 따로 전달하지 않고 a List<String>
를 가져 와서 얻을 수없는 근본적인 이유 String[]
입니다. 컴포넌트 유형 정보가없는 것에서 컴포넌트 유형 정보를 가져와야합니다. 분명히 이것은 불가능합니다.
나는 때때로 배열을 만드는 대신 반복자를 사용할 수 있고 사용할 것입니다. 그러나 이것은 항상 나에게 이상하게 보였습니다. get (x) 메서드가 반환하는 내용을 알고 있지만 toArray ()가 기본적으로 Objects로 설정되는 이유는 무엇입니까? 그것을 디자인하는 절반 정도 그들은 이것이 여기에 필요하지 않다고 결정했습니다 ??
질문의 의도는 toArray()
제네릭을 사용 하는 것뿐만 아니라 ArrayList
클래스 의 메서드 디자인을 이해하는 것이므로 다음을 추가하고 싶습니다.
ArrayList
다음과 같이 선언 된 일반 클래스입니다.
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
public E get(int index)
클래스 내에서 와 같은 Generic 메서드를 사용할 수 있습니다 .
그러나 toArray()
is not returning 과 같은 메소드 가 E
오히려 E[]
조금 까다로워지기 시작합니다. public <E> E[] toArray()
일반적인 배열을 만들 수 없기 때문에 같은 서명을 제공 할 수 없습니다.
배열 생성은 런타임에 발생하며 유형 삭제 로 인해 Java 런타임에는로 표시되는 유형의 특정 정보가 없습니다 E
. 현재 유일한 해결 방법은 필수 유형을 매개 변수로 메소드 public <T> T[] toArray(T[] a)
에 전달하는 것이므로 클라이언트가 필수 유형을 전달해야하는 서명 을 전달하는 것입니다.
그러나 반면에 public E get(int index)
메서드 구현을 보면 메서드가 동일한 Object 배열을 사용하여 지정된 인덱스의 요소를 반환하더라도 다음으로 캐스팅된다는 것을 알 수 있기 때문에 작동합니다.E
E elementData(int index) {
return (E) elementData[index];
}
컴파일 시간에 다음으로 대체되는 Java 컴파일러 E
입니다.Object
배열은 배열의 유형과 다른 유형입니다. String 클래스가 아닌 일종의 StringArray 클래스입니다.
가능하다고 가정하면 Generic 메서드 toArray()
는 다음과 같습니다.
private <T> T[] toArray() {
T[] result = new T[length];
//populate
return result;
}
이제 컴파일 중에 T 유형이 지워집니다. 부품은 어떻게 new T[length]
교체해야합니까? 일반 유형 정보를 사용할 수 없습니다.
If you look at the source code of (for example) ArrayList
, you see the same. The toArray(T[] a)
method either fills the given array (if the size matches) or creates a new new array using the type of the parameter, which is the array-type of the Generic Type T.
The very first thing you have to understand is what ArrayList
own is just an array of Object
transient Object[] elementData;
When it comes to the reason why T[]
is fail, it because you can't get an array of generic type without a Class<T>
and this is because java's type erase( there is a more explanation and how to create one). And the array[]
on the heap knows its type dynamically and you can't cast int[]
to String[]
. The same reason, you can't cast Object[]
to T[]
.
int[] ints = new int[3];
String[] strings = (String[]) ints;//java: incompatible types: int[] cannot be converted to java.lang.String[]
public <T> T[] a() {
Object[] objects = new Object[3];
return (T[])objects;
}
//ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
Integer[] a = new LearnArray().<Integer>a();
But what you put into the array
is just a object which type is E
(which is checked by compiler), so you can just cast it to E
which is safe and correct.
return (E) elementData[index];
In short, you can't get what don't have by cast. You have just Object[]
, so toArray()
can just return Object[]
(otherwise, you have to give it a Class<T>
to make a new array with this type). You put E
in ArrayList<E>
, you can get a E
with get()
.
It is possible to create a "generic" array of the given(known) type. Normally I use something like this in my code.
public static <T> T[] toArray(Class<T> type, ArrayList<T> arrList) {
if ((arrList == null) || (arrList.size() == 0)) return null;
Object arr = Array.newInstance(type, arrList.size());
for (int i=0; i < arrList.size(); i++) Array.set(arr, i, arrList.get(i));
return (T[])arr;
}
ReferenceURL : https://stackoverflow.com/questions/36598928/java-generics-in-arraylist-toarray
'program tip' 카테고리의 다른 글
정의되지 않은 JSON.stringify를 유지하면 그렇지 않으면 제거됩니다. (0) | 2020.12.24 |
---|---|
XMLHttpRequest 모듈이 정의되지 않음 / 찾음 (0) | 2020.12.24 |
따옴표 사이의 경우를 제외하고 Java의 공백에서 문자열 분할 (예 : \ "hello world \"를 하나의 토큰으로 취급) (0) | 2020.12.15 |
Wordpress를 Django 또는 Ruby on Rails와 같은 프레임 워크로 대체 할 수 있습니까? (0) | 2020.12.15 |
쉘 스크립트에서 여러 줄 출력 들여 쓰기 (0) | 2020.12.15 |