Java에서 범용 어레이 유형을 생성할 수 없는 이유는 무엇입니까?
왜 자바가 이 일을 못하게 하는 거죠?
private T[] elements = new T[initialCapacity];
나는 이해할 수 있었다.NET 에서는, 에서와 같이, 이것을 실시할 수 없었습니다.NET에는 런타임에 다른 크기를 가질 수 있는 값 유형이 있지만 Java에서는 모든 종류의 T가 오브젝트 참조가 되기 때문에 크기가 동일합니다(잘못되면 정정해 주세요).
이유가 뭐야?
Java의 어레이(제너릭과 달리)는 런타임에 컴포넌트 유형에 대한 정보를 포함하고 있기 때문입니다.따라서 배열을 생성할 때 구성 요소 유형을 알아야 합니다.T
실행 시 어레이를 생성할 수 없습니다.
견적:
일반 유형의 배열은 소리가 나지 않으므로 허용되지 않습니다.이 문제는 Java 어레이가 정적으로 건전하지는 않지만 동적으로 체크되는 것과 정적으로 건전하고 동적으로 체크되지 않는 제네릭과의 상호작용에 기인합니다.이 허점을 이용하는 방법은 다음과 같습니다.
class Box<T> { final T x; Box(T x) { this.x = x; } } class Loophole { public static void main(String[] args) { Box<String>[] bsa = new Box<String>[3]; Object[] oa = bsa; oa[0] = new Box<Integer>(3); // error not caught by array store check String s = bsa[0].x; // BOOM! } }
Tiger에서 거부된 정적 안전 어레이(Variance)를 사용하여 이 문제를 해결할 것을 제안했습니다.
-- gafter(가후)
(Neal Gafter라고 믿지만 확실하지 않습니다.)
자세한 것은, http://forums.sun.com/thread.jspa?threadID=457033&forumID=316 를 참조해 주세요.
적절한 해결책을 제시하지 못하면 더 나쁜 IMHO를 얻게 됩니다.
일반적인 작업은 다음과 같습니다.
T[] ts = new T[n];
로 대체됩니다(T가 다른 클래스가 아닌 객체를 확장한다고 가정함).
T[] ts = (T[]) new Object[n];
나는 첫 번째 예를 선호하지만, 더 많은 학문적 유형들이 두 번째를 선호하거나 그냥 그것에 대해 생각하지 않는 것을 선호하는 것 같다.
오브젝트 []를 사용할 수 없는 이유의 대부분은 목록 또는 컬렉션(지원 대상)에 동일하게 적용되기 때문에 매우 빈약한 인수라고 생각합니다.
주의: 이것이 Collections 라이브러리 자체가 경고 없이 컴파일되지 않는 이유 중 하나입니다.경고 없이 이 사용 사례를 지원할 수 없는 경우 범용 모델 IMHO에서 근본적으로 문제가 발생한 것입니다.
이것이 불가능한 이유는 Java가 Generics를 컴파일러 레벨로만 구현하고 클래스별로 생성되는 클래스 파일은 1개뿐이기 때문입니다.이를 유형 삭제라고 합니다.
실행 시 컴파일된 클래스는 동일한 바이트 코드를 사용하여 모든 사용을 처리해야 합니다.so,는,new T[capacity]
어떤 타입이 인스턴스화 되어야 하는지 전혀 알지 못할 겁니다
이미 답변이 제공되었지만 이미 T 인스턴스가 있는 경우 다음을 수행할 수 있습니다.
T t; //Assuming you already have this object instantiated or given by parameter.
int length;
T[] ts = (T[]) Array.newInstance(t.getClass(), length);
호프, 내가 도울 수 있어, Ferdi265
주된 이유는 Java의 배열이 공변량이기 때문입니다.
여기에 좋은 개요가 있습니다.
나는 Gafter의 간접적인 답변을 좋아한다.하지만, 나는 그것이 틀렸다고 제안한다.Gafter의 코드를 조금 바꿨어요.컴파일해서 잠시 작동하다가 가프터가 예상한 곳에 폭탄을 터뜨리고
class Box<T> {
final T x;
Box(T x) {
this.x = x;
}
}
class Loophole {
public static <T> T[] array(final T... values) {
return (values);
}
public static void main(String[] args) {
Box<String> a = new Box("Hello");
Box<String> b = new Box("World");
Box<String> c = new Box("!!!!!!!!!!!");
Box<String>[] bsa = array(a, b, c);
System.out.println("I created an array of generics.");
Object[] oa = bsa;
oa[0] = new Box<Integer>(3);
System.out.println("error not caught by array store check");
try {
String s = bsa[0].x;
} catch (ClassCastException cause) {
System.out.println("BOOM!");
cause.printStackTrace();
}
}
}
출력은
I created an array of generics.
error not caught by array store check
BOOM!
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at Loophole.main(Box.java:26)
범용 어레이 타입은 Java로 작성할 수 있는 것 같습니다.제가 질문을 잘못 이해했나요?
Oracle 튜토리얼에서:
매개 변수화된 유형의 배열은 생성할 수 없습니다.예를 들어, 다음 코드는 컴파일되지 않습니다.
List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-time error
다음 코드는 어레이에 다른 유형을 삽입할 때 발생하는 작업을 보여 줍니다.
Object[] strings = new String[2]; strings[0] = "hi"; // OK strings[1] = 100; // An ArrayStoreException is thrown.
일반 목록에서도 같은 작업을 시도하면 다음과 같은 문제가 발생합니다.
Object[] stringLists = new List<String>[]; // compiler error, but pretend it's allowed stringLists[0] = new ArrayList<String>(); // OK stringLists[1] = new ArrayList<Integer>(); // An ArrayStoreException should be thrown, // but the runtime can't detect it.
파라미터화된 리스트의 배열을 허용하면 이전 코드는 원하는 ArrayStoreException을 슬로우할 수 없습니다.
저한테는 아주 약하게 들리는데요.제네릭스에 대해 충분히 이해하고 있는 사람이라면 ArrayStoredException이 이 경우 폐기되지 않을 것으로 생각됩니다.
여기 파티에 조금 늦은 건 알지만, 이 대답들 중 어느 것도 제 문제를 해결해주지 못했기 때문에 미래의 구글 이용자들을 도울 수 있을 것 같아서요.하지만 Ferdi265의 답변은 큰 도움이 되었다.
독자적인 링크 리스트를 작성하려고 하고 있기 때문에, 다음의 코드가 유효합니다.
package myList;
import java.lang.reflect.Array;
public class MyList<TYPE> {
private Node<TYPE> header = null;
public void clear() { header = null; }
public void add(TYPE t) { header = new Node<TYPE>(t,header); }
public TYPE get(int position) { return getNode(position).getObject(); }
@SuppressWarnings("unchecked")
public TYPE[] toArray() {
TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());
for(int i=0 ; i<size() ; i++) result[i] = get(i);
return result;
}
public int size(){
int i = 0;
Node<TYPE> current = header;
while(current != null) {
current = current.getNext();
i++;
}
return i;
}
toArray() 메서드에서는 범용 타입의 배열을 작성하는 방법이 있습니다.
TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());
제 경우, 다음과 같은 스택을 배열하고 싶었을 뿐입니다.
Stack<SomeType>[] stacks = new Stack<SomeType>[2];
이것이 불가능했기 때문에 회피책으로 다음 사항을 사용했습니다.
- 스택 주위에 일반 래퍼 클래스가 아닌 래퍼 클래스 생성(MyStack 등)
- MyStack[] 스택 = 새 MyStack[2]이(가) 완벽하게 작동했습니다.
못생겼지만 자바는 행복해.
주의: BrainSlugs83이 질문 코멘트에서 언급한 바와 같이 에는 제네릭 배열이 완전히 존재할 수 있습니다.그물
자바를 만든 후에 제네릭스가 추가되었기 때문에 자바의 오리지널 메이커는 배열을 만들 때 타입이 지정된다고 생각했기 때문에 다소 투박합니다.범용 기기에서는 동작하지 않기 때문에 E[] array=(E[]) 새로운 오브젝트[15]를 실행해야 합니다.이것은 컴파일되지만 경고를 줍니다.
class는 타입 T[]의 배열을 선언할 수 있지만 이러한 배열을 직접 인스턴스화할 수는 없습니다.대신, 일반적인 접근법은 Object[] 유형의 배열을 인스턴스화한 후 다음과 같이 T[] 유형으로 좁혀 캐스트를 만드는 것입니다.
public class Portfolio<T> {
T[] data;
public Portfolio(int capacity) {
data = new T[capacity]; // illegal; compiler error
data = (T[]) new Object[capacity]; // legal, but compiler warning
}
public T get(int index) { return data[index]; }
public void set(int index, T element) { data[index] = element; }
}
엔 그게 것 때문이다.ArrayList.toArray(T[] a)
래요 요인인:
public <T> T[] toArray(T[] a)
이 목록의 모든 요소를 포함하는 배열을 올바른 순서로 반환합니다. 반환된 배열의 런타임 유형은 지정된 배열의 유형입니다.목록이 지정된 배열에 맞으면 해당 배열로 반환됩니다.그렇지 않으면 지정된 어레이의 런타임 유형과 이 목록의 크기를 사용하여 새 어레이가 할당됩니다.
이 ', '만들다', '만들다', '만들다', '만들다'를 만드는 방법이 있습니다.ArrayList
중 합니다.toArray(T[] a)
실제 어레이를 만듭니다.빠르지는 않겠지만, 당신은 당신의 요구 사항을 언급하지 않았습니다.
어떻게 하는지 사람 요?toArray(T[] a)
현되어? ??
범용 어레이를 인스턴스화할 수 없는 경우 해당 언어에 범용 어레이 유형이 있는 이유는 무엇입니까?물건이 없는 활자는 무슨 소용입니까?
가 생각할 수 유일한 - ar the the the 、 the the the the the-foo(T...)
그렇지 않으면 범용 어레이 유형을 완전히 스크럽할 수 있습니다.(varargs는 1.5 이전 버전에는 존재하지 않았기 때문에 varargs에 어레이를 사용할 필요가 없었습니다.또 다른 실수일 수도 있습니다.)
즉, varargs를 통해 범용 어레이를 인스턴스화할 수 있습니다.
물론 일반 어레이의 문제는 여전히 존재합니다.
static <T> T[] foo(T... args){
return args;
}
static <T> T[] foo2(T a1, T a2){
return foo(a1, a2);
}
public static void main(String[] args){
String[] x2 = foo2("a", "b"); // heap pollution!
}
이 예를 사용하여 범용 어레이의 위험을 실제로 설명할 수 있습니다.
반면에, 우리는 10년 동안 범용 변종을 사용해 왔고, 아직 하늘은 무너지지 않고 있습니다.그래서 우리는 그 문제들이 과장되고 있다고 주장할 수 있다; 그것은 큰 문제가 아니다.명시적인 범용 어레이 작성이 허용되면 여기저기서 버그가 발생할 수 있습니다.그러나, 소거에 관한 문제는 이미 익숙해져 있기 때문에, 그 문제는 충분히 견딜 수 있습니다.
그리고 우리가 지적할 수 있는 것은foo2
스펙이 우리를 방해한다고 주장하는 문제로부터 우리를 보호한다는 주장을 반박하기 위해서입니다.만약 Sun이 1.5를 위해 더 많은 시간과 자원을 가지고 있었다면, 나는 그들이 더 만족스러운 해결책에 도달했을 것이라고 믿는다.
이미 언급한 바와 같이 몇 가지 트릭을 사용하여 만들 수 있습니다.
하지만 추천하지 않습니다.
왜냐하면 타입 삭제와 더 중요한 것은covariance
서브타입 배열을 슈퍼타입 배열에 할당할 수 있는 어레이에서 실행시간을 발생시키는 값을 되돌리려고 할 때 명시적인 타입 캐스트를 사용하도록 강제합니다.ClassCastException
이는 제네릭이 배제하려고 하는 주요 목표 중 하나입니다.컴파일 시 강력한 유형 검사.
Object[] stringArray = { "hi", "me" };
stringArray[1] = 1;
String aString = (String) stringArray[1]; // boom! the TypeCastException
보다 직접적인 예는 Effective Java에서 찾을 수 있습니다. 항목 25.
공분산: S가 T의 하위 유형인 경우 S[] 유형의 배열은 T의 하위 유형입니다.
[]; // OK
단, T의 배열은 인스턴스화할 수 없습니다// vals = new T[10];// T의 배열을 생성할 수 없습니다.
T의 배열을 작성할 수 없는 이유는 컴파일러가 실제로 작성하는 배열 유형을 알 수 없기 때문입니다.
이것을 시험해 보세요.
List<?>[] arrayOfLists = new List<?>[4];
언급URL : https://stackoverflow.com/questions/2927391/whats-the-reason-i-cant-create-generic-array-types-in-java
'sourcecode' 카테고리의 다른 글
어떻게 하면 WAMP에서 마리아db를 제대로 제거할 수 있을까? (0) | 2022.09.05 |
---|---|
WHERE 절에서 mysql SUM()을 사용합니다. (0) | 2022.09.05 |
개체 배열에서 .join on 값을 수행합니다. (0) | 2022.09.05 |
Node.js에서 MySQL(ORM 없음)을 어떻게 조롱합니까? (0) | 2022.09.05 |
MySQL: 저장 프로시저에서 여러 필드를 여러 변수로 선택 (0) | 2022.09.05 |