Reputation: 1218
I'm currently running java 7 and I found java has an odd behavior in a specific situation. The code below shows the next() of an iterator for a generic Trie data structure:
public final Iterator iterator = new Iterator()
{
private int objsProcessed = 0;
private K currentKeySequence = null;
@Override
public boolean hasNext()
{
return objsProcessed < numObjects;
}
@Override
public Object next()
{
if (keySequences.isEmpty() == false)
{
currentKeySequence = keySequences.get(objsProcessed);
}
else
{
return null;
}
objsProcessed++;
Character[] test=new Character[]{'a','b'};
Object result = reference.get(test);
result = reference.get(currentKeySequence);
return result;
}
@Override
public void remove()
{
reference.remove(currentKeySequence);
}
};
Keys sequences are added in the following:
public Trie add(V object, K... keySequence)
{
Node<K, V> currentNode = root;
for (int i = 0; i < keySequence.length; i++)
{
currentNode = currentNode.insert(new Node<K, V>(keySequence[i],
currentNode));
}
currentNode.addObject(object);
keySequences.add((K) keySequence);
numObjects++;
return this;
}
The get method takes a variable number of arguments:
public List<V> get(K... keySequence)
{
Node<K, V> currentNode = root;
for (int i = 0; i < keySequence.length; i++)
{
currentNode = currentNode.getNode(keySequence[i]);
}
if (currentNode != null)
return currentNode.getObjects();
else
return null;
}
The problem is that when I pass the currentKeySequence which is, in my test case, a Character[] of size 2, it makes the keySequence variable actually be an array of size 1 that contains currentKeySequence instead of just being currentKeySequence (size 2). If instead of currentKeySequence, I pass new Character[]{'a','b'} it works as expected without putting the array inside a wrapper array.
Update: In other words, I have currentKeySequence = test = Character[]{'a','b'} where the only difference is that currentKeySequence is retrieved from a list and the var test is instantiated locally with the "new" keyword.
If I pass the var test, then keySequence=Character[]{'a','b'} and if I pass currentKeySequence, then keySequence=Object[]{Character[]{'a','b'}}. I know that if I call get('a','b'), keySequence would be a Object[]{'a','b'}. I would expect that if the parameter is always wrapped into an array both situations would be the same.
Am I doing something wrong or is this a bug?
Upvotes: 0
Views: 538
Reputation: 1218
The problem was the line
private K currentKeySequence = null;
K was Character but the var currentKeySequence was being assigned to Character[] (K[]). No issues were visible in the debugger or raised during runtime but when the variable was passed as parameter it was arriving in the method as Object[]{Character[]{...}}. Once K was changed to K[] in the currentKeySequence definition, the method received the correct parameter (just Character[]{...});
Upvotes: 0
Reputation: 106470
Your varargs structure is doing what it's told. It's encapsulating everything you give it into an array of some type K
.
If you pass an array of arrays; that is to say, if you pass in something that could be expanded to be a two-dimensional array, then the varargs will interpret that as a single argument to the varargs array.
In your question, this too would be considered a two-dimensional array:
new Object[]{new Character[]{'a','b'}}
The reason: it's a Character[]
nested inside of an Object[]
(which is totally legal).
Upvotes: 2
Reputation: 15146
It's not a bug. That's how varags work.
Variable arguments (varags) allow you to pass in no argument or multiple arguments. To allow this, it uses an array to track the arguments. A single argument is not special; it's stored in the first index of the array.
Its always good to check if the array contains items before performing anything, since the client can specify no arguments for the parameter.
Upvotes: 3