views:

94

answers:

3

Java Class java.lang.reflect.Array provides a set of tools for creating an array dynamically. However in addition to that it has a whole set of methods for accessing (get, set, and length) an array. I don't understand the point of this, since you can (and presumably would) cast your dynamically generated array as an array upon creation, which means you can use the normal array access (bracket notation) functionality. In fact, looking at the source code you can see that is all the class does, cast the array, and throw an exception if the cast fails.

So what's the point / usefulness of all of these extra methods?

Update

All of the primitive get*() and set*() methods seem especially unhelpful, considering you need to know the type of the array beforehand in order to know which method to use.

Update 2

Thanks everyone, your input has been very educational! I can't really see when I'd be using this class for anything other than newInstance(), but I now realize these other methods are still quite useful.

+1  A: 

These methods relieve you from the burden of checking and casting the array yourself, if all you know is "that object is an array of some (possibly primitive) type".

I myself have seen uses of this only in frameworks and utilities, like commons-beanutils. This framework reflectively accesses properties of java beans, and uses the Array methods to access elements of array properties.

Christian Semrau
Could you provide an example? I downloaded the source for commons-beanutils and look for references of the Array class, but did not see any.
dimo414
A grep for `java.lang.reflect.Array` should have returned a few results. Have a look at `BeanUtilsBean` and `PropertyUtilsBean` in the `org.apache.commons.beanutils` package.
Christian Semrau
Heh, I guess Windows "full-text search" isn't very full text at all. Thanks.
dimo414
Hehe, that's exactly my finding, too. I just found a [MS knowledge base article](http://support.microsoft.com/kb/309173) that seems to explain the behaviour (at least for XP): In short, Windows file search is "too clever" to perform a full text search.
Christian Semrau
+1  A: 

This class is quite esoteric - most uses of arrays know the type of the array, so this class is typically most useful when implementing code that handles arrays generically.

There is no array superclass for all arrays, so there is no uniform way of accessing elements or the size of an array regardless of type. The java.lang.reflect.Array fills this gap and allows you to access the array in the same way regardless from type. For example, to get the value at a given index from any array (returned as an object).

It's parameteric polymorphism. Sure, you could code this yourself if you know the type - you just cast. If you don't know the array type, or it can be several types, you would check the possibilities and cast appropriately - which is what the code in reflect.Array does.

EDIT: In response to the comment. Consider how you would solve this problem - how to count the number of times a value is duplicated in an array. Without the type-agnostic Array class, this would not be possible to code, without explicitly casting the array, so you would need a different function for each array type. Here, we have one function that handles any type of array.

public Map<Object, Integer> countDuplicates(Object anArray)
{
    if (!anArray.getClass().isArray())
        throw new IllegalArgumentException("anArray is not an array");

    Map<Object,Integer> dedup = new HashMap<Object,Integer>();
    int length = Array.getLength(anArray);
    for (int i=0; i<length; i++)
    {
        Object value = Array.get(anArray, i);         
        Integer count = dedup.get(value);
        dedup.put(value, count==null ? 1 : count+1);
    }
    return dedup;
}

EDIT2: Regarding the get*() and set*() methods. The source code link above links to Apache harmony. The implementation there does not adhere to the Sun Javadocs. For example, from the getInt method

@throws IllegalArgumentException If the specified object is not an array, 
or if the indexed element cannot be converted to the return type 
by an identity or widening conversion 

This implies that the actual array could be byte[], short[] or int[]. This is not the case with the Harmony implementation, which only takes an int[]. (Incidentally, the Sun implementation uses native methods for most of the Array class.) The get*() and set*() methods are there for the same reason as get(), getLength() - to provide (loosely) type-agnostic array access.

Not exactly something you need to use every day, but I imagine it provides value for those that need it.

mdma
I don't understand what you mean, the standard bracket notation is uniform over all types, including primitives. Since as you note it returns an Object, you ultimately still have to do a cast - either the object or the array. Therefore why wouldn't you just cast the array?
dimo414
There are use cases where you don't care about the types. You don't need to cast. For example, counting duplicate values in an array. I've updated my answer with a code sample.
mdma
Well, I'll grant you that is /a/ use case. I still feel like these methods are pretty contrived, but I see your point.
dimo414
Still, the primitive get/set methods do seem useless, don't they?
dimo414
Please see my latest edit.
mdma
Wow, somehow I'd never realized docjar wasn't the Sun implementation!
dimo414
Thanks for helping me understand the usefulness of this.
dimo414
No problem. It's pretty unusual, but not entirely useless. (I've never needed to use it before.)
mdma
+1  A: 

Regarding the set...() methods, they do provide some use:

Object a = new byte[1], b = new short[1], c = new int[1], d = new long[1];
Array.setByte(a, 0, (byte)1);
Array.setByte(b, 0, (byte)1);
Array.setByte(c, 0, (byte)1);
Array.setByte(d, 0, (byte)1);

You don't need to know whether the array you're dealing with is an int[] or a long[] to set a value to 5, for example.

Edit I changed the example to hopefully demonstrate the fact that set...() methods allow you to not necessarily know the primitive array's type statically.

Mark Peters
byte[] b = new byte[1];short[] s = new short[1];int[] i = new int[1];long[] l = new long[1];b[0] = (byte)1;s[0] = (byte)1;i[0] = (byte)1;l[0] = (byte)1;Works just as well...
dimo414
Eh, it screwed up my new lines.
dimo414
@dimo414: You're missing the point in all of this. You can't use the [] operator unless it's an array. You can't cast to an array when it's a primitive array unless you know the primitive type. So if you were writing a library function that should accept `byte[]`, `short[]`, `long[]`, or `int[]` and set the first element to 5, you'd have to do four `instanceof` checks to determine the type, then cast it to the respective primitive array, and then do the assignment. `Array.setByte(someArrayRef, 0, (byte)5)` does the same thing as a one-liner.
Mark Peters
I getcha. I guess I was struggling to wrap my head around /why/ you'd ever have that situation, but now it makes more sense.
dimo414