ArrayList 변환 to String [] 배열 [duplicate]
이 질문에 이미 답변이 있습니다.
나는 안드로이드 환경에서 일하고 있으며 다음 코드를 시도했지만 작동하지 않는 것 같습니다.
String [] stockArr = (String[]) stock_list.toArray();
다음과 같이 정의하면 :
String [] stockArr = {"hello", "world"};
효과가있다. 내가 놓친 것이 있습니까?
이렇게 사용하십시오.
List<String> stockList = new ArrayList<String>();
stockList.add("stock1");
stockList.add("stock2");
String[] stockArr = new String[stockList.size()];
stockArr = stockList.toArray(stockArr);
for(String s : stockArr)
System.out.println(s);
이 시도
String[] arr = list.toArray(new String[list.size()]);
무엇이 일어나는 것은 즉 stock_list.toArray()
생성되는 Object[]
(A)보다 오히려을 String[]
따라서 배역 실패한다 (1) .
올바른 코드는 다음과 같습니다.
String [] stockArr = stockList.toArray(new String[stockList.size()]);
또는
String [] stockArr = stockList.toArray(new String[0]);
자세한 내용은 .NET의 두 가지 오버로드에 대한 javadocs를 참조하세요 List.toArray
.
후자의 버전은 길이가 0 인 배열을 사용하여 결과 배열의 유형을 결정합니다. (놀랍게도 최근 Java 릴리스의 경우 ...을 미리 할당하는 것보다이 작업을 수행하는 것이 더 빠릅니다. 자세한 내용은 https://stackoverflow.com/a/4042464/139985 를 참조하십시오.)
기술적 인 관점에서이 API 동작 / 설계의 이유는 List<T>.toArray()
메서드 구현 <T>
에 런타임시 의 정보가 없기 때문 입니다. 아는 것은 원시 요소 유형이 Object
. 반대로 다른 경우에는 array 매개 변수가 배열의 기본 유형을 제공합니다. (제공된 배열이 목록 요소를 보유 할만큼 충분히 크면 사용됩니다. 그렇지 않으면 동일한 유형 및 더 큰 크기의 새 배열이 할당되어 결과로 반환됩니다.)
1 - 자바에서,이 Object[]
와 호환 할당되지 않습니다 String[]
. 그렇다면 다음과 같이 할 수 있습니다.
Object[] objects = new Object[]{new Cat("fluffy")};
Dog[] dogs = (Dog[]) objects;
Dog d = dogs[0]; // Huh???
이것은 분명히 말도 안되는 일이며, 이것이 배열 유형이 일반적으로 할당 호환되지 않는 이유입니다.
Java 8의 대안 :
String[] strings = list.stream().toArray(String[]::new);
문제를 해결하는 방법을 보여주는 많은 답변을 볼 수 있지만 문제가 발생하는 이유를 설명하려는 것은 Stephen의 답변 뿐 이므로이 주제에 대해 더 많은 것을 추가해 보겠습니다. 제네릭웨어가 Java에 도입 된 곳으로 Object[] toArray
변경되지 않은 이유에 대한 이야기 T[] toArray
입니다.
왜 String[] stockArr = (String[]) stock_list.toArray();
작동하지 않습니까?
Java에서 제네릭 유형은 컴파일 타임에만 존재합니다 . 런타임시 제네릭 유형에 대한 정보 (예 : 귀하의 경우 <String>
)가 제거되고 Object
유형으로 대체됩니다 ( 유형 삭제 살펴보기 ). 그렇기 때문에 런타임에 toArray()
새 배열을 만드는 데 사용할 정확한 유형을 알지 못하므로 Object
가장 안전한 유형으로 사용합니다. 각 클래스는 Object를 확장하여 모든 클래스의 인스턴스를 안전하게 저장할 수 있기 때문입니다.
이제 문제는의 인스턴스 Object[]
를 String[]
.
왜? 이 예제를 살펴보십시오 (가정하자 class B extends A
).
//B extends A
A a = new A();
B b = (B)a;
Although such code will compile, at runtime we will see thrown ClassCastException
because instance held by reference a
is not actually of type B
(or its subtypes). Why is this problem (why this exception needs to be cast)? One of the reasons is that B
could have new methods/fields which A
doesn't, so it is possible that someone will try to use these new members via b
reference even if held instance doesn't have (doesn't support) them. In other words we could end up trying to use data which doesn't exist, which could lead to many problems. So to prevent such situation JVM throws exception, and stop further potentially dangerous code.
You could ask now "So why aren't we stopped even earlier? Why code involving such casting is even compilable? Shouldn't compiler stop it?". Answer is: no because compiler can't know for sure what is the actual type of instance held by a
reference, and there is a chance that it will hold instance of class B
which will support interface of b
reference. Take a look at this example:
A a = new B();
// ^------ Here reference "a" holds instance of type B
B b = (B)a; // so now casting is safe, now JVM is sure that `b` reference can
// safely access all members of B class
Now lets go back to your arrays. As you see in question, we can't cast instance of Object[]
array to more precise type String[]
like
Object[] arr = new Object[] { "ab", "cd" };
String[] arr2 = (String[]) arr;//ClassCastException will be thrown
Here problem is a little different. Now we are sure that String[]
array will not have additional fields or methods because every array support only:
[]
operator,length
filed,- methods inherited from Object supertype,
So it is not arrays interface which is making it impossible. Problem is that Object[]
array beside Strings
can store any objects (for instance Integers
) so it is possible that one beautiful day we will end up with trying to invoke method like strArray[i].substring(1,3)
on instance of Integer
which doesn't have such method.
So to make sure that this situation will never happen, in Java array references can hold only
- instances of array of same type as reference (reference
String[] strArr
can holdString[]
) - instances of array of subtype (
Object[]
can holdString[]
becauseString
is subtype ofObject
),
but can't hold
- array of supertype of type of array from reference (
String[]
can't holdObject[]
) - array of type which is not related to type from reference (
Integer[]
can't holdString[]
)
In other words something like this is OK
Object[] arr = new String[] { "ab", "cd" }; //OK - because
// ^^^^^^^^ `arr` holds array of subtype of Object (String)
String[] arr2 = (String[]) arr; //OK - `arr2` reference will hold same array of same type as
// reference
You could say that one way to resolve this problem is to find at runtime most common type between all list elements and create array of that type, but this wont work in situations where all elements of list will be of one type derived from generic one. Take a look
//B extends A
List<A> elements = new ArrayList<A>();
elements.add(new B());
elements.add(new B());
now most common type is B
, not A
so toArray()
A[] arr = elements.toArray();
would return array of B
class new B[]
. Problem with this array is that while compiler would allow you to edit its content by adding new A()
element to it, you would get ArrayStoreException
because B[]
array can hold only elements of class B
or its subclass, to make sure that all elements will support interface of B
, but instance of A
may not have all methods/fields of B
. So this solution is not perfect.
Best solution to this problem is explicitly tell what type of array toArray()
should be returned by passing this type as method argument like
String[] arr = list.toArray(new String[list.size()]);
or
String[] arr = list.toArray(new String[0]); //if size of array is smaller then list it will be automatically adjusted.
The correct way to do this is:
String[] stockArr = stock_list.toArray(new String[stock_list.size()]);
I'd like to add to the other great answers here and explain how you could have used the Javadocs to answer your question.
The Javadoc for toArray()
(no arguments) is here. As you can see, this method returns an Object[]
and not String[]
which is an array of the runtime type of your list:
public Object[] toArray()
Returns an array containing all of the elements in this collection. If the collection makes any guarantees as to what order its elements are returned by its iterator, this method must return the elements in the same order. The returned array will be "safe" in that no references to it are maintained by the collection. (In other words, this method must allocate a new array even if the collection is backed by an Array). The caller is thus free to modify the returned array.
Right below that method, though, is the Javadoc for toArray(T[] a)
. As you can see, this method returns a T[]
where T
is the type of the array you pass in. At first this seems like what you're looking for, but it's unclear exactly why you're passing in an array (are you adding to it, using it for just the type, etc). The documentation makes it clear that the purpose of the passed array is essentially to define the type of array to return (which is exactly your use case):
public <T> T[] toArray(T[] a)
Returns an array containing all of the elements in this collection; the runtime type of the returned array is that of the specified array. If the collection fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this collection. If the collection fits in the specified array with room to spare (i.e., the array has more elements than the collection), the element in the array immediately following the end of the collection is set to null. This is useful in determining the length of the collection only if the caller knows that the collection does not contain any null elements.)
If this collection makes any guarantees as to what order its elements are returned by its iterator, this method must return the elements in the same order.
This implementation checks if the array is large enough to contain the collection; if not, it allocates a new array of the correct size and type (using reflection). Then, it iterates over the collection, storing each object reference in the next consecutive element of the array, starting with element 0. If the array is larger than the collection, a null is stored in the first location after the end of the collection.
Of course, an understanding of generics (as described in the other answers) is required to really understand the difference between these two methods. Nevertheless, if you first go to the Javadocs, you will usually find your answer and then see for yourself what else you need to learn (if you really do).
Also note that reading the Javadocs here helps you to understand what the structure of the array you pass in should be. Though it may not really practically matter, you should not pass in an empty array like this:
String [] stockArr = stockList.toArray(new String[0]);
Because, from the doc, this implementation checks if the array is large enough to contain the collection; if not, it allocates a new array of the correct size and type (using reflection). There's no need for the extra overhead in creating a new array when you could easily pass in the size.
As is usually the case, the Javadocs provide you with a wealth of information and direction.
Hey wait a minute, what's reflection?
참고URL : https://stackoverflow.com/questions/5374311/convert-arrayliststring-to-string-array
'development' 카테고리의 다른 글
Django는 확장됩니까? (0) | 2020.09.27 |
---|---|
Node.js에 파일 / 디렉토리가 있는지 동 기적으로 확인 (0) | 2020.09.27 |
주어진 요소에 클래스를 어떻게 추가합니까? (0) | 2020.09.27 |
Node.js의 Express.js에서 GET (쿼리 문자열) 변수를 얻는 방법은 무엇입니까? (0) | 2020.09.27 |
git : 새 파일을 포함하여 모든 작업 디렉토리 변경을 취소합니다. (0) | 2020.09.27 |