Java Generic problems.

To keep it short:
I’ve got this method:


public void query([...], List<QuadtreeElement /*, which is an interface */> results) { [...] }

And I want to call it like that:


ArrayList<Element /*, which implements QuadtreeElement*/> list = new ArrayList<Element>();
tree.query([...], list);

The problem/error that I get is this one:

[quote]The method query([…], List) in the type Quadtree is not applicable for the arguments ([…], ArrayList<Quadtree.Elem>)
[/quote]
I also tried:


public void query([...], List<E extends QuadtreeElement> result) { [...] }

But this throws this error:

[quote]Syntax error on token “extends”, , expected
[/quote]

They’re called generics, not templates. Expecting C++ template-like behavior will lead to heartbreak. Anyway, you’re 99% of the way there – you just need to replace ‘E’ with ‘?’ so you end up with:

public void query([...], List<? extends QuadtreeElement> result) { [...] }

http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

just a quick question about what you do with this “result” collection.

Do you fill it with elements in your querry method?
If I think it is not the good of a idea, beside then you should use an upper and not a lower bound. ? super CLASS instead of ? extends CLASS

Good catch. If query can only return QuadtreeElement, you can’t make it fill a List any more than a method returning Object can populate a String variable. Obviously if your query is actually getting Element instances, you can downcast them, but it’s not a terribly good idea.

This thread does an amazing job at explaining it: http://stackoverflow.com/questions/591004/generics-super-t

The choice of names is really confusing BTW, because it looks like Element should be the interface and QuadtreeElement the implementation.

Mhmmm… so I tried this out:


public void query([...], List<? extends QuadtreeElement> results) { [...] }

Which didn’nt work. It gave me this error on a later “results.add([QuadtreeElement])” (The problem is, that I don’t know which QuadtreeElement implementing class is actually is:

[quote]The method add(capture#1-of ? extends QuadtreeElement) in the type List<capture#1-of ? extends QuadtreeElement> is not applicable for the arguments (QuadtreeElement)
[/quote]
The problem on the later call of “query” didn’t throw any errors.

So I changed it to:


public void query([...], List<? super QuadtreeElement> results) { [...] }

So now the Error on the “results.add([QuadtreeElement])” is gone, but the error on the “tree.query([…], [ArrayList])” is back:

[quote]The method query(StaticRect, List<? super QuadtreeElement>) in the type Quadtree is not applicable for the arguments (StaticRect, ArrayList<Quadtree.Element/Mind that there is the dot/>)
[/quote]
Also, since this might be helpful, here is the almost-complete source-code:
[Offtopic: Riven, the pastbin seems to be broken:
“8: Undefined variable: seek
File: /home/jgo/public_html/addon_pastebin.php
Line: 12”
So I just post it as normal pastebin:]
http://pastebin.com/C0RsHqip

I need help… :confused:

The problem with using “Quadtree” is, that this would not be working:


elements = new E[elemPerQuad]; // See in the constructor

I hope you can help me :slight_smile:

EDIT:

Yes I do fill it with “results.add([QuadtreeElement])”…

Ooookey. I fixed it. JGO’s pastebin is still not working for me…
The source code will be posted on “Shared Code” :slight_smile:
(Editing link into it, for everyone googleing this.)
EDIT:
The Topic

elements = new E[elemPerQuad]; // See in the constructor

Can’t be done. Anything that needs the type of E at runtime is impossible. In this one case, it’s easily fixed, just change elements to List. Other cases where you need something like ‘new E’ you’re out of luck

I solved it by using

elements = (E[])(new QuadtreeElement[elementsPerQuad]); // suppressing a warning here :)

Does it even makes sense?

Yes.
EDIT: Detailed question. Detailed answer :wink:

Sorry I don’t see why…

I mean you can do the following :


List list = new ArrayList();

but you can’t do it the other way around


ArrayList list = new List(); //Don't tell me you can't instanciate List directly, I know...

but I need to add that the following can make sense


ArrayList list = (ArrayList) listInstance; //Will work if listInstance was already an instance of ArrayList

I did that because, just as sproingie said:

So I did a workaround.
I casted a newly-created Array to the specified chosen “E”-Array. I can be sure, that E extends QuadtreeElement, so I choose it. I could have also used Object, that was just for readablility.

You could try it out yourself: use QuadtreeElement[] yourself. You will get an error, because you can’t assign a QuadtreeElement[] to E[]. So you need to cast that array to E[].

(ArrayList) new List();

Is not equal to

new ArrayList()

That’s basically what you seems to be trying to do here with

elements = (E[])(new QuadtreeElement[elementsPerQuad]); // suppressing a warning here :)

Yes but objects are still different from Arrays. In the end I’m casting ints to ints or longs to longs and only change the “mark”, which type of class is used for this Array.
What I can tell you is: it does not work without this workaround. This workaround is solid, and works for every case :wink:

Strange when I try to run the following code in eclipse it crash :

public class TypeArray {
	
	public static void main(String [] args){
		String[] array = (String[]) (new Object[10]);
	}

}

with that exception

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
	at test.TypeArray.main(TypeArray.java:6)

Because an Object is not a String, but the other way around is true:


Object[] array = (Object[]) new String[10];

To get a String array from an Object array, you’d need to do something like this:

String[] s = new String[other.length];
for (int i=0; i<other.length; i++) {
    s[i] = other[i]!=null ? other[i].toString() : null;
}

Though generally speaking you’ll never need to deal with the Object class if you use generics wisely. :slight_smile:

EDIT: I sorta jumped in instead of reading the thread. But I’ll leave this here, anyways…

Guys I know full well that Object is not a String, if you read the thread carefully you will see that I’m trying to help Matheus23.

Am-I the only one that see something really strange in his code?

Actually I don’t have any problems now. They are all solved.
That code I wrote gives me a warning, but it actually can’t crash, so why bother?

Also, thank you for trying to help me, but currently you only said, that that code part didn’t make sense, and why. You didn’t even give me another option, or an Idea of how to do it another way.

elements = (E[])(new QuadtreeElement[elemPerQuad]);

How about this?

List<E> elements = new ArrayList<E>(elemPerQuad);