001/* java.lang.reflect.Array - manipulate arrays by reflection
002   Copyright (C) 1998, 1999, 2001, 2003, 2005  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.lang.reflect;
040
041/**
042 * Array holds static helper functions that allow you to create and
043 * manipulate arrays by reflection. Operations know how to perform widening
044 * conversions, but throw {@link IllegalArgumentException} if you attempt
045 * a narrowing conversion. Also, when accessing primitive arrays, this
046 * class performs object wrapping and unwrapping as necessary.<p>
047 *
048 * <B>Note:</B> This class returns and accepts types as Classes, even
049 * primitive types; there are Class types defined that represent each
050 * different primitive type.  They are <code>java.lang.Boolean.TYPE,
051 * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class,
052 * byte.class</code>, etc.  These are not to be confused with the
053 * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are
054 * real classes. Note also that the shorthand <code>Object[].class</code>
055 * is a convenient way to get array Classes.<p>
056 *
057 * <B>Performance note:</B> This class performs best when it does not have
058 * to convert primitive types.  The further along the chain it has to convert,
059 * the worse performance will be.  You're best off using the array as whatever
060 * type it already is, and then converting the result.  You will do even
061 * worse if you do this and use the generic set() function.
062 *
063 * @author John Keiser
064 * @author Eric Blake (ebb9@email.byu.edu)
065 * @author Per Bothner (bothner@cygnus.com)
066 * @see java.lang.Boolean#TYPE
067 * @see java.lang.Byte#TYPE
068 * @see java.lang.Short#TYPE
069 * @see java.lang.Character#TYPE
070 * @see java.lang.Integer#TYPE
071 * @see java.lang.Long#TYPE
072 * @see java.lang.Float#TYPE
073 * @see java.lang.Double#TYPE
074 * @since 1.1
075 * @status updated to 1.4
076 */
077public final class Array
078{
079
080  /**
081   * This class is uninstantiable.
082   */
083  private Array()
084  {
085  }
086
087  /**
088   * Creates a new single-dimensioned array.
089   * @param componentType the type of the array to create
090   * @param length the length of the array to create
091   * @return the created array, cast to an Object
092   * @throws NullPointerException if <code>componentType</code> is null
093   * @throws IllegalArgumentException if <code>componentType</code> is
094   *         <code>Void.TYPE</code>
095   * @throws NegativeArraySizeException when length is less than 0
096   * @throws OutOfMemoryError if memory allocation fails
097   */
098  public static Object newInstance(Class<?> componentType, int length)
099  {
100    if (! componentType.isPrimitive())
101      return VMArray.createObjectArray(componentType, length);
102    if (componentType == boolean.class)
103      return new boolean[length];
104    if (componentType == byte.class)
105      return new byte[length];
106    if (componentType == char.class)
107      return new char[length];
108    if (componentType == short.class)
109      return new short[length];
110    if (componentType == int.class)
111      return new int[length];
112    if (componentType == long.class)
113      return new long[length];
114    if (componentType == float.class)
115      return new float[length];
116    if (componentType == double.class)
117      return new double[length];
118    // assert componentType == void.class
119    throw new IllegalArgumentException();
120  }
121
122  /**
123   * Creates a new multi-dimensioned array.  The new array has the same
124   * component type as the argument class, and the number of dimensions
125   * in the new array is the sum of the dimensions of the argument class
126   * and the length of the argument dimensions. Virtual Machine limitations
127   * forbid too many dimensions (usually 255 is the maximum); but even
128   * 50 dimensions of 2 elements in each dimension would exceed your memory
129   * long beforehand!
130   *
131   * @param componentType the type of the array to create.
132   * @param dimensions the dimensions of the array to create.  Each element
133   *        in <code>dimensions</code> makes another dimension of the new
134   *        array.  Thus, <code>Array.newInstance(java.lang.Boolean,
135   *        new int[]{1,2,3})</code> is the same as
136   *        <code>new java.lang.Boolean[1][2][3]</code>
137   * @return the created array, cast to an Object
138   * @throws NullPointerException if componentType or dimension is null
139   * @throws IllegalArgumentException if the the size of
140   *         <code>dimensions</code> is 0 or exceeds the maximum number of
141   *         array dimensions in the VM; or if componentType is Void.TYPE
142   * @throws NegativeArraySizeException when any of the dimensions is less
143   *         than 0
144   * @throws OutOfMemoryError if memory allocation fails
145   */
146  public static Object newInstance(Class<?> componentType, int[] dimensions)
147  {
148    if (dimensions.length <= 0)
149      throw new IllegalArgumentException ("Empty dimensions array.");
150    return createMultiArray(componentType, dimensions, 0);
151  }
152
153  /**
154   * Gets the array length.
155   * @param array the array
156   * @return the length of the array
157   * @throws IllegalArgumentException if <code>array</code> is not an array
158   * @throws NullPointerException if <code>array</code> is null
159   */
160  public static int getLength(Object array)
161  {
162    if (array instanceof Object[])
163      return ((Object[]) array).length;
164    if (array instanceof boolean[])
165      return ((boolean[]) array).length;
166    if (array instanceof byte[])
167      return ((byte[]) array). length;
168    if (array instanceof char[])
169      return ((char[]) array).length;
170    if (array instanceof short[])
171      return ((short[]) array).length;
172    if (array instanceof int[])
173      return ((int[]) array).length;
174    if (array instanceof long[])
175      return ((long[]) array).length;
176    if (array instanceof float[])
177      return ((float[]) array).length;
178    if (array instanceof double[])
179      return ((double[]) array).length;
180    if (array == null)
181      throw new NullPointerException();
182    throw new IllegalArgumentException();
183  }
184
185  /**
186   * Gets an element of an array.  Primitive elements will be wrapped in
187   * the corresponding class type.
188   *
189   * @param array the array to access
190   * @param index the array index to access
191   * @return the element at <code>array[index]</code>
192   * @throws IllegalArgumentException if <code>array</code> is not an array
193   * @throws NullPointerException if <code>array</code> is null
194   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
195   *         bounds
196   * @see #getBoolean(Object, int)
197   * @see #getByte(Object, int)
198   * @see #getChar(Object, int)
199   * @see #getShort(Object, int)
200   * @see #getInt(Object, int)
201   * @see #getLong(Object, int)
202   * @see #getFloat(Object, int)
203   * @see #getDouble(Object, int)
204   */
205  public static Object get(Object array, int index)
206  {
207    if (array instanceof Object[])
208      return ((Object[]) array)[index];
209    if (array instanceof boolean[])
210      return ((boolean[]) array)[index] ? Boolean.TRUE : Boolean.FALSE;
211    if (array instanceof byte[])
212      return Byte.valueOf(((byte[]) array)[index]);
213    if (array instanceof char[])
214      return Character.valueOf(((char[]) array)[index]);
215    if (array instanceof short[])
216      return Short.valueOf(((short[]) array)[index]);
217    if (array instanceof int[])
218      return Integer.valueOf(((int[]) array)[index]);
219    if (array instanceof long[])
220      return Long.valueOf(((long[]) array)[index]);
221    if (array instanceof float[])
222      return Float.valueOf(((float[]) array)[index]);
223    if (array instanceof double[])
224      return Double.valueOf(((double[]) array)[index]);
225    if (array == null)
226      throw new NullPointerException();
227    throw new IllegalArgumentException();
228  }
229
230  /**
231   * Gets an element of a boolean array.
232   *
233   * @param array the array to access
234   * @param index the array index to access
235   * @return the boolean element at <code>array[index]</code>
236   * @throws IllegalArgumentException  if <code>array</code> is not a boolean
237   *         array
238   * @throws NullPointerException if <code>array</code> is null
239   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
240   *         bounds
241   * @see #get(Object, int)
242   */
243  public static boolean getBoolean(Object array, int index)
244  {
245    if (array instanceof boolean[])
246      return ((boolean[]) array)[index];
247    if (array == null)
248      throw new NullPointerException();
249    throw new IllegalArgumentException();
250  }
251
252  /**
253   * Gets an element of a byte array.
254   *
255   * @param array the array to access
256   * @param index the array index to access
257   * @return the byte element at <code>array[index]</code>
258   * @throws IllegalArgumentException  if <code>array</code> is not a byte
259   *         array
260   * @throws NullPointerException if <code>array</code> is null
261   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
262   *         bounds
263   * @see #get(Object, int)
264   */
265  public static byte getByte(Object array, int index)
266  {
267    if (array instanceof byte[])
268      return ((byte[]) array)[index];
269    if (array == null)
270      throw new NullPointerException();
271    throw new IllegalArgumentException();
272  }
273
274  /**
275   * Gets an element of a char array.
276   *
277   * @param array the array to access
278   * @param index the array index to access
279   * @return the char element at <code>array[index]</code>
280   * @throws IllegalArgumentException  if <code>array</code> is not a char
281   *         array
282   * @throws NullPointerException if <code>array</code> is null
283   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
284   *         bounds
285   * @see #get(Object, int)
286   */
287  public static char getChar(Object array, int index)
288  {
289    if (array instanceof char[])
290      return ((char[]) array)[index];
291    if (array == null)
292      throw new NullPointerException();
293    throw new IllegalArgumentException();
294  }
295
296  /**
297   * Gets an element of a short array.
298   *
299   * @param array the array to access
300   * @param index the array index to access
301   * @return the short element at <code>array[index]</code>
302   * @throws IllegalArgumentException  if <code>array</code> is not a byte
303   *         or char array
304   * @throws NullPointerException if <code>array</code> is null
305   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
306   *         bounds
307   * @see #get(Object, int)
308   */
309  public static short getShort(Object array, int index)
310  {
311    if (array instanceof short[])
312      return ((short[]) array)[index];
313    return getByte(array, index);
314  }
315
316  /**
317   * Gets an element of an int array.
318   *
319   * @param array the array to access
320   * @param index the array index to access
321   * @return the int element at <code>array[index]</code>
322   * @throws IllegalArgumentException  if <code>array</code> is not a byte,
323   *         char, short, or int array
324   * @throws NullPointerException if <code>array</code> is null
325   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
326   *         bounds
327   * @see #get(Object, int)
328   */
329  public static int getInt(Object array, int index)
330  {
331    if (array instanceof int[])
332      return ((int[]) array)[index];
333    if (array instanceof char[])
334      return ((char[]) array)[index];
335    return getShort(array, index);
336  }
337
338  /**
339   * Gets an element of a long array.
340   *
341   * @param array the array to access
342   * @param index the array index to access
343   * @return the long element at <code>array[index]</code>
344   * @throws IllegalArgumentException  if <code>array</code> is not a byte,
345   *         char, short, int, or long array
346   * @throws NullPointerException if <code>array</code> is null
347   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
348   *         bounds
349   * @see #get(Object, int)
350   */
351  public static long getLong(Object array, int index)
352  {
353    if (array instanceof long[])
354      return ((long[]) array)[index];
355    return getInt(array, index);
356  }
357
358  /**
359   * Gets an element of a float array.
360   *
361   * @param array the array to access
362   * @param index the array index to access
363   * @return the float element at <code>array[index]</code>
364   * @throws IllegalArgumentException  if <code>array</code> is not a byte,
365   *         char, short, int, long, or float array
366   * @throws NullPointerException if <code>array</code> is null
367   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
368   *         bounds
369   * @see #get(Object, int)
370   */
371  public static float getFloat(Object array, int index)
372  {
373    if (array instanceof float[])
374      return ((float[]) array)[index];
375    return getLong(array, index);
376  }
377
378  /**
379   * Gets an element of a double array.
380   *
381   * @param array the array to access
382   * @param index the array index to access
383   * @return the double element at <code>array[index]</code>
384   * @throws IllegalArgumentException  if <code>array</code> is not a byte,
385   *         char, short, int, long, float, or double array
386   * @throws NullPointerException if <code>array</code> is null
387   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
388   *         bounds
389   * @see #get(Object, int)
390   */
391  public static double getDouble(Object array, int index)
392  {
393    if (array instanceof double[])
394      return ((double[]) array)[index];
395    return getFloat(array, index);
396  }
397
398  /**
399   * Sets an element of an array. If the array is primitive, then the new
400   * value is unwrapped and widened.
401   *
402   * @param array the array to set a value of
403   * @param index the array index to set the value to
404   * @param value the value to set
405   * @throws IllegalArgumentException if <code>array</code> is not an array,
406   *         or the array is primitive and unwrapping value fails, or the
407   *         value is not assignable to the array component type
408   * @throws NullPointerException if array is null, or if array is primitive
409   *         and value is null
410   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
411   *         bounds
412   * @see #setBoolean(Object, int, boolean)
413   * @see #setByte(Object, int, byte)
414   * @see #setChar(Object, int, char)
415   * @see #setShort(Object, int, short)
416   * @see #setInt(Object, int, int)
417   * @see #setLong(Object, int, long)
418   * @see #setFloat(Object, int, float)
419   * @see #setDouble(Object, int, double)
420   */
421  public static void set(Object array, int index, Object value)
422  {
423    if (array instanceof Object[])
424      {
425        // Too bad the API won't let us throw the easier ArrayStoreException!
426        if (value != null
427            && ! array.getClass().getComponentType().isInstance(value))
428          throw new IllegalArgumentException();
429        ((Object[]) array)[index] = value;
430      }
431    else if (value instanceof Byte)
432      setByte(array, index, ((Byte) value).byteValue());
433    else if (value instanceof Short)
434      setShort(array, index, ((Short) value).shortValue());
435    else if (value instanceof Integer)
436      setInt(array, index, ((Integer) value).intValue());
437    else if (value instanceof Long)
438      setLong(array, index, ((Long) value).longValue());
439    else if (value instanceof Float)
440      setFloat(array, index, ((Float) value).floatValue());
441    else if (value instanceof Double)
442      setDouble(array, index, ((Double) value).doubleValue());
443    else if (value instanceof Character)
444      setChar(array, index, ((Character) value).charValue());
445    else if (value instanceof Boolean)
446      setBoolean(array, index, ((Boolean) value).booleanValue());
447    else if (array == null)
448      throw new NullPointerException();
449    else
450      throw new IllegalArgumentException();
451  }
452
453  /**
454   * Sets an element of a boolean array.
455   *
456   * @param array the array to set a value of
457   * @param index the array index to set the value to
458   * @param value the value to set
459   * @throws IllegalArgumentException if <code>array</code> is not a boolean
460   *         array
461   * @throws NullPointerException if <code>array</code> is null
462   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
463   *         bounds
464   * @see #set(Object, int, Object)
465   */
466  public static void setBoolean(Object array, int index, boolean value)
467  {
468    if (array instanceof boolean[])
469      ((boolean[]) array)[index] = value;
470    else if (array == null)
471      throw new NullPointerException();
472    else
473      throw new IllegalArgumentException();
474  }
475
476  /**
477   * Sets an element of a byte array.
478   *
479   * @param array the array to set a value of
480   * @param index the array index to set the value to
481   * @param value the value to set
482   * @throws IllegalArgumentException if <code>array</code> is not a byte,
483   *         short, int, long, float, or double array
484   * @throws NullPointerException if <code>array</code> is null
485   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
486   *         bounds
487   * @see #set(Object, int, Object)
488   */
489  public static void setByte(Object array, int index, byte value)
490  {
491    if (array instanceof byte[])
492      ((byte[]) array)[index] = value;
493    else
494      setShort(array, index, value);
495  }
496
497  /**
498   * Sets an element of a char array.
499   *
500   * @param array the array to set a value of
501   * @param index the array index to set the value to
502   * @param value the value to set
503   * @throws IllegalArgumentException if <code>array</code> is not a char,
504   *         int, long, float, or double array
505   * @throws NullPointerException if <code>array</code> is null
506   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
507   *         bounds
508   * @see #set(Object, int, Object)
509   */
510  public static void setChar(Object array, int index, char value)
511  {
512    if (array instanceof char[])
513      ((char[]) array)[index] = value;
514    else
515      setInt(array, index, value);
516  }
517
518  /**
519   * Sets an element of a short array.
520   *
521   * @param array the array to set a value of
522   * @param index the array index to set the value to
523   * @param value the value to set
524   * @throws IllegalArgumentException if <code>array</code> is not a short,
525   *         int, long, float, or double array
526   * @throws NullPointerException if <code>array</code> is null
527   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
528   *         bounds
529   * @see #set(Object, int, Object)
530   */
531  public static void setShort(Object array, int index, short value)
532  {
533    if (array instanceof short[])
534      ((short[]) array)[index] = value;
535    else
536      setInt(array, index, value);
537  }
538
539  /**
540   * Sets an element of an int array.
541   *
542   * @param array the array to set a value of
543   * @param index the array index to set the value to
544   * @param value the value to set
545   * @throws IllegalArgumentException if <code>array</code> is not an int,
546   *         long, float, or double array
547   * @throws NullPointerException if <code>array</code> is null
548   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
549   *         bounds
550   * @see #set(Object, int, Object)
551   */
552  public static void setInt(Object array, int index, int value)
553  {
554    if (array instanceof int[])
555      ((int[]) array)[index] = value;
556    else
557      setLong(array, index, value);
558  }
559
560  /**
561   * Sets an element of a long array.
562   *
563   * @param array the array to set a value of
564   * @param index the array index to set the value to
565   * @param value the value to set
566   * @throws IllegalArgumentException if <code>array</code> is not a long,
567   *         float, or double array
568   * @throws NullPointerException if <code>array</code> is null
569   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
570   *         bounds
571   * @see #set(Object, int, Object)
572   */
573  public static void setLong(Object array, int index, long value)
574  {
575    if (array instanceof long[])
576      ((long[]) array)[index] = value;
577    else
578      setFloat(array, index, value);
579  }
580
581  /**
582   * Sets an element of a float array.
583   *
584   * @param array the array to set a value of
585   * @param index the array index to set the value to
586   * @param value the value to set
587   * @throws IllegalArgumentException if <code>array</code> is not a float
588   *         or double array
589   * @throws NullPointerException if <code>array</code> is null
590   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
591   *         bounds
592   * @see #set(Object, int, Object)
593   */
594  public static void setFloat(Object array, int index, float value)
595  {
596    if (array instanceof float[])
597      ((float[]) array)[index] = value;
598    else
599      setDouble(array, index, value);
600  }
601
602  /**
603   * Sets an element of a double array.
604   *
605   * @param array the array to set a value of
606   * @param index the array index to set the value to
607   * @param value the value to set
608   * @throws IllegalArgumentException if <code>array</code> is not a double
609   *         array
610   * @throws NullPointerException if <code>array</code> is null
611   * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
612   *         bounds
613   * @see #set(Object, int, Object)
614   */
615  public static void setDouble(Object array, int index, double value)
616  {
617    if (array instanceof double[])
618      ((double[]) array)[index] = value;
619    else if (array == null)
620      throw new NullPointerException();
621    else
622      throw new IllegalArgumentException();
623  }
624
625  /**
626   * Dynamically and recursively create a multi-dimensioned array of objects.
627   *
628   * @param type guaranteed to be a valid object type
629   * @param dimensions the dimensions of the array
630   * @param index index of the current dimension to build
631   * @return the new multi-dimensioned array
632   * @throws NegativeArraySizeException if any entry of dimensions is negative
633   * @throws OutOfMemoryError if memory allocation fails
634   */
635  // This would be faster if implemented natively, using the multianewarray
636  // bytecode instead of this recursive call
637  private static Object createMultiArray(Class type, int[] dimensions,
638                                         int index)
639  {
640    if (index == dimensions.length - 1)
641      return newInstance(type, dimensions[index]);
642
643    Object toAdd = createMultiArray(type, dimensions, index + 1);
644    Class thisType = toAdd.getClass();
645    Object[] retval
646      = (Object[]) VMArray.createObjectArray(thisType, dimensions[index]);
647    if (dimensions[index] > 0)
648      retval[0] = toAdd;
649    int i = dimensions[index];
650    while (--i > 0)
651      retval[i] = createMultiArray(type, dimensions, index + 1);
652    return retval;
653  }
654
655}