source

Java Generics: 목록에 캐스트할 수 없는가?

manysource 2022. 12. 13. 20:10

Java Generics: 목록에 캐스트할 수 없는가?

이 문제에 대해 생각해 보세요.

List<DataNode> a1 = new ArrayList<DataNode>();
List<Tree> b1 = a1;  // compile error: incompatible type

여기서 DataNode 유형은 트리의 하위 유형입니다.

public class DataNode implements Tree

놀랍게도, 이것은 어레이에 유효합니다.

DataNode[] a2 = new DataNode[0];
Tree[] b2 = a2;   // this is okay

이거 좀 이상한데?누가 이것에 대해 설명해 줄 수 있나요?

두 번째 예에서는 어레이 공분산입니다.IMO는 어레이 내의 할당이 안전하지 않게 되어 컴파일 시에는 정상이지만 실행 시에는 실패할 수 있습니다.

첫 번째 예에서는 코드가 컴파일되고 그 뒤에 다음이 이어졌다고 가정합니다.

b1.add(new SomeOtherTree());
DataNode node = a1.get(0);

무슨 일이 일어날 것 같습니까?

다음과 같이 할 수 있습니다.

List<DataNode> a1 = new ArrayList<DataNode>();
List<? extends Tree> b1 = a1;

당신은 ...에서 수 이다.그러면 당신은 오직 물건만 가져올 수 있기 때문이다.b1, ,, 음, 음, 이, 음, 음, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ible, ible, ible, , ible, ible,Tree 하면 안 b1.add(...)컴파일러가 안전한지 아닌지 알 수 없기 때문입니다.

자세한 내용은 Angelika Langer의 Java Generics FAQ 섹션을 참조하십시오.

을 해야 List<DataNode>로로 합니다.List<Tree>그렇게 하는 것이 안전하다는 것을 알고 있습니다.그러기 위해서는 더블캐스트를 하는 것이 바람직하지 않습니다.

List<DataNode> a1 = new ArrayList<DataNode>();

List<Tree> b1 = (List<Tree>) (List<? extends Tree>) a1;

간단한 설명: 어레이에 대해 처음에 허용한 것은 실수였습니다.

자세한 설명:

이것이 허용되었다고 가정합니다.

List<DataNode> a1 = new ArrayList<DataNode>();
List<Tree> b1 = a1;  // pretend this is allowed

그럼 다음 순서로 진행하면 안 될까요?

b1.add(new TreeThatIsntADataNode()); // Hey, b1 is a List<Tree>, so this is fine

for (DataNode dn : a1) {
  // Uh-oh!  There's stuff in a1 that isn't a DataNode!!
}

으로서는 ''을할 때 을 할 수 .List를 사용하고 있는 (예를 들면, 「」를 참조).List범용 에 대해 수 없습니다., 이 Java없습니다.List<A> a까지List<B>~가 아니면A ★★★★★★★★★★★★★★★★★」B똑같았어요.

(*) 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 맞다.할 수 .List<? extends Tree>츠키노

List<DataNode>하지 않다List<Tree>DataNode를 확장하다Tree)를 할 수 ADATANode)는, 「a1」의 「Data Node」의 「Data Node」의 「ADATANode」를 참조해 주세요.

와일드카드를 사용하여 다음과 같은 작업을 수행해야 합니다.

List<DataNode> a1 = new ArrayList<DataNode>();
List<? extends Tree> b1 = a1;
b1.add(new Tree()); // compiler error, instead of runtime error

★★★★★★★★★★★★★★★★.DataNode[] ★★Tree[]당시에는 당연한 것처럼 보였지만 다음과 같은 작업을 수행할 수 있습니다.

DataNode[] a2 = new DataNode[1];
Tree[] b2 = a2; // this is okay
b2[0] = new Tree(); // this will cause ArrayStoreException since b2 is actually a DataNode[] and can't store a Tree

그렇기 때문에 컬렉션에 제네릭을 추가할 때 런타임 오류를 방지하기 위해 조금 다른 방법을 선택했습니다.

어레이가 설계되었을 때(즉, Java가 설계되었을 때) 개발자들은 분산이 유용하다고 판단하여 이를 허용했습니다. 이 하게 하기 에, 를 들면, 이 결정으로 인해).NotADataNode의 또 입니다.Tree

DataNode[] a2 = new DataNode[1];
Tree[] b2 = a2;   // this is okay
b2[0] = new NotADataNode(); //compiles fine, causes runtime error

수 없다, 할 수 없다, 수 없다, 할 수 , 할 수 할 수 없다.List<Tree> b1 = a1;할 수 있어요.List<? extends Tree> b1 = a1;.

후자의 , 「」를 ,add ★★★★★★★★★★★★★★★★★」set 방법을 )T인수로)를 지정하면 컴파일 오류가 발생합니다.이렇게 하면 (안전하지 않은 캐스팅이 없으면) 위의 어레이 문제와 동등한 문제를 컴파일할 수 없습니다.

간단한 답변: 목록 a1은 목록 b2와 같은 유형이 아닙니다.a1에는 확장 DataNode를 사용하여 임의의 객체 유형을 넣을 수 있습니다.따라서 Tree 이외의 타입을 포함할 수 있습니다.

C#의 답변입니다만, 이유는 같기 때문에, 이쪽에서는 그다지 문제가 되지 않는다고 생각합니다.

특히 어레이 유형과 달리 구성된 참조 유형은 "공변" 변환을 나타내지 않습니다.이것은, 타입 List<B>가 List<로의 변환(암묵적 또는 명시적)이 없는 것을 의미합니다.A>B가 A에서 파생된 경우에도.마찬가지로 List <B>에서 List <object>로의 변환은 없습니다.

그 이유는 간단합니다.목록으로 변환하는 경우<A > 가 허가되어 있기 때문에, 타입 A 의 값을 리스트에 격납할 수 있는 것이 분명합니다.단, 이로 인해 유형 목록 내의 모든 객체가 항상 유형 B의 값이라는 불변성이 깨집니다.그렇지 않으면 컬렉션 클래스에 할당할 때 예기치 않은 장애가 발생할 수 있습니다."

http://social.msdn.microsoft.com/forums/en-US/clr/thread/22e262ed-c3f8-40ed-baf3-2cbcc54a216e

DataNode는 트리의 하위 유형일 수 있지만 List DataNode는 List Tree의 하위 유형이 아닙니다.

https://docs.oracle.com/javase/tutorial/extra/generics/subtype.html

이것은 타입 삭제 기능을 실장하고 있는 제네릭의 전형적인 문제입니다.

첫 번째 예가 제대로 작동했다고 가정해 보십시오.그러면 다음 작업을 수행할 수 있습니다.

List<DataNode> a1 = new ArrayList<DataNode>();
List<Tree> b1 = a1;  // suppose this works
b1.add(new Tree());

하지만 그 이후로는b1그리고.a1같은 대상을 가리키다, 그것은 곧 을 의미한다.a1이제 를 참조합니다.List양쪽 모두를 지탱하는DataNodeTrees. 마지막 요소를 가져오려고 하면 예외가 발생합니다(어느 요소가 기억나지 않음).

자, 여기서 솔직하게 말씀드리겠습니다. 게으른 일반성의 구현입니다.

첫 번째 감정을 허락하지 않을 의미 있는 이유는 없어요.

덧붙여서, 저는 C++로 템플리트를 만드는 것을 좋아했지만, 제네릭스와 여기에 있는 바보 같은 제약이 제가 Java를 포기한 주된 이유입니다.

언급URL : https://stackoverflow.com/questions/3246137/java-generics-cannot-cast-listsubclass-to-listsuperclass