Array.java revision f6c387128427e121477c1b32ad35cdcaa5101ba3
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17/*
18 * Copyright (C) 2008 The Android Open Source Project
19 *
20 * Licensed under the Apache License, Version 2.0 (the "License");
21 * you may not use this file except in compliance with the License.
22 * You may obtain a copy of the License at
23 *
24 *      http://www.apache.org/licenses/LICENSE-2.0
25 *
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS,
28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 * See the License for the specific language governing permissions and
30 * limitations under the License.
31 */
32
33package java.lang.reflect;
34
35/**
36 * This class provides static methods to create and access arrays dynamically.
37 *
38 * @since Android 1.0
39 */
40public final class Array {
41
42    /**
43     * Prevent this class from being instantiated.
44     */
45    private Array(){
46        //do nothing
47    }
48
49    /**
50     * Returns the element of the array at the specified index. This reproduces
51     * the effect of {@code array[index]}. If the array component is a primitive
52     * type, the result is automatically wrapped.
53     *
54     * @param array
55     *            the array
56     * @param index
57     *            the index
58     *
59     * @return the requested element, possibly wrapped
60     *
61     * @throws NullPointerException
62     *             if the array is null
63     * @throws IllegalArgumentException
64     *             if {@code array} is not an array
65     * @throws ArrayIndexOutOfBoundsException
66     *             if {@code  index < 0 || index >= array.length}
67     *
68     * @since Android 1.0
69     */
70    public static Object get(Object array, int index)
71            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
72        if (array instanceof Object[])
73            return ((Object[]) array)[index];
74
75        if (array instanceof boolean[])
76            return ((boolean[]) array)[index] ? Boolean.TRUE : Boolean.FALSE;
77
78        if (array instanceof byte[])
79            return new Byte(((byte[]) array)[index]);
80
81        if (array instanceof char[])
82            return new Character(((char[]) array)[index]);
83
84        if (array instanceof short[])
85            return new Short(((short[]) array)[index]);
86
87        if (array instanceof int[])
88            return new Integer(((int[]) array)[index]);
89
90        if (array instanceof long[])
91            return new Long(((long[]) array)[index]);
92
93        if (array instanceof float[])
94            return new Float(((float[]) array)[index]);
95
96        if (array instanceof double[])
97            return new Double(((double[]) array)[index]);
98
99        if (array == null)
100            throw new NullPointerException();
101
102        throw new IllegalArgumentException("Not an array");
103    }
104
105    /**
106     * Returns the element of the array at the specified index, converted to a
107     * {@code boolean}, if possible. This reproduces the effect of {@code
108     * array[index]}
109     *
110     * @param array
111     *            the array
112     * @param index
113     *            the index
114     *
115     * @return the requested element
116     *
117     * @throws NullPointerException
118     *             if the {@code array} is {@code null}
119     * @throws IllegalArgumentException
120     *             if {@code array} is not an array or the element at the
121     *             index position can not be converted to the return type
122     * @throws ArrayIndexOutOfBoundsException
123     *             if {@code index < 0 || index >= array.length}
124     *
125     * @since Android 1.0
126     */
127    public static boolean getBoolean(Object array, int index)
128            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
129        if (array instanceof boolean[]) {
130            return ((boolean[]) array)[index];
131        } else if (array == null) {
132            throw new NullPointerException();
133        } else if (array.getClass().isArray()) {
134            throw new IllegalArgumentException("Wrong array type");
135        } else {
136            throw new IllegalArgumentException("Not an array");
137        }
138    }
139
140    /**
141     * Returns the element of the array at the specified index, converted to a
142     * {@code byte}, if possible. This reproduces the effect of {@code
143     * array[index]}
144     *
145     * @param array
146     *            the array
147     * @param index
148     *            the index
149     *
150     * @return the requested element
151     *
152     * @throws NullPointerException
153     *             if the {@code array} is {@code null}
154     * @throws IllegalArgumentException
155     *             if {@code array} is not an array or the element at the
156     *             index position can not be converted to the return type
157     * @throws ArrayIndexOutOfBoundsException
158     *             if {@code index < 0 || index >= array.length}
159     *
160     * @since Android 1.0
161     */
162    public static byte getByte(Object array, int index)
163            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
164        if (array instanceof byte[]) {
165            return ((byte[]) array)[index];
166        } else {
167            return getBoolean(array, index) ? (byte)1 : (byte)0;
168        }
169    }
170
171    /**
172     * Returns the element of the array at the specified index, converted to a
173     * {@code char}, if possible. This reproduces the effect of {@code
174     * array[index]}
175     *
176     * @param array
177     *            the array
178     * @param index
179     *            the index
180     *
181     * @return the requested element
182     *
183     * @throws NullPointerException
184     *             if the {@code array} is {@code null}
185     * @throws IllegalArgumentException
186     *             if {@code array} is not an array or the element at the
187     *             index position can not be converted to the return type
188     * @throws ArrayIndexOutOfBoundsException
189     *             if {@code index < 0 || index >= array.length}
190     *
191     * @since Android 1.0
192     */
193    public static char getChar(Object array, int index)
194            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
195        if (array instanceof char[]) {
196            return ((char[]) array)[index];
197        } else if (array == null) {
198            throw new NullPointerException();
199        } else if (array.getClass().isArray()) {
200            throw new IllegalArgumentException("Wrong array type");
201        } else {
202            throw new IllegalArgumentException("Not an array");
203        }
204    }
205
206    /**
207     * Returns the element of the array at the specified index, converted to a
208     * {@code double}, if possible. This reproduces the effect of {@code
209     * array[index]}
210     *
211     * @param array
212     *            the array
213     * @param index
214     *            the index
215     *
216     * @return the requested element
217     *
218     * @throws NullPointerException
219     *             if the {@code array} is {@code null}
220     * @throws IllegalArgumentException
221     *             if {@code array} is not an array or the element at the
222     *             index position can not be converted to the return type
223     * @throws ArrayIndexOutOfBoundsException
224     *             if {@code index < 0 || index >= array.length}
225     *
226     * @since Android 1.0
227     */
228    public static double getDouble(Object array, int index)
229            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
230        if (array instanceof double[]) {
231            return ((double[]) array)[index];
232        } else {
233            return getFloat(array, index);
234        }
235    }
236
237    /**
238     * Returns the element of the array at the specified index, converted to a
239     * {@code float}, if possible. This reproduces the effect of {@code
240     * array[index]}
241     *
242     * @param array
243     *            the array
244     * @param index
245     *            the index
246     *
247     * @return the requested element
248     *
249     * @throws NullPointerException
250     *             if the {@code array} is {@code null}
251     * @throws IllegalArgumentException
252     *             if {@code array} is not an array or the element at the
253     *             index position can not be converted to the return type
254     * @throws ArrayIndexOutOfBoundsException
255     *             if {@code index < 0 || index >= array.length}
256     *
257     * @since Android 1.0
258     */
259    public static float getFloat(Object array, int index)
260            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
261        if (array instanceof float[]) {
262            return ((float[]) array)[index];
263        } else {
264            return getLong(array, index);
265        }
266    }
267
268    /**
269     * Returns the element of the array at the specified index, converted to an
270     * {@code int}, if possible. This reproduces the effect of {@code
271     * array[index]}
272     *
273     * @param array
274     *            the array
275     * @param index
276     *            the index
277     *
278     * @return the requested element
279     *
280     * @throws NullPointerException
281     *             if the {@code array} is {@code null}
282     * @throws IllegalArgumentException
283     *             if {@code array} is not an array or the element at the
284     *             index position can not be converted to the return type
285     * @throws ArrayIndexOutOfBoundsException
286     *             if {@code index < 0 || index >= array.length}
287     *
288     * @since Android 1.0
289     */
290    public static int getInt(Object array, int index)
291            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
292        if (array instanceof int[]) {
293            return ((int[]) array)[index];
294        } else {
295            return getShort(array, index);
296        }
297    }
298
299    /**
300     * Returns the length of the array. This reproduces the effect of {@code
301     * array.length}
302     *
303     * @param array
304     *            the array
305     *
306     * @return the length of the array
307     *
308     * @throws NullPointerException
309     *             if the {@code array} is {@code null}
310     * @throws IllegalArgumentException
311     *             if {@code array} is not an array
312     *
313     * @since Android 1.0
314     */
315    public static int getLength(Object array) {
316        if (array instanceof Object[])
317            return ((Object[]) array).length;
318
319        if (array instanceof boolean[])
320            return ((boolean[]) array).length;
321
322        if (array instanceof byte[])
323            return ((byte[]) array).length;
324
325        if (array instanceof char[])
326            return ((char[]) array).length;
327
328        if (array instanceof short[])
329            return ((short[]) array).length;
330
331        if (array instanceof int[])
332            return ((int[]) array).length;
333
334        if (array instanceof long[])
335            return ((long[]) array).length;
336
337        if (array instanceof float[])
338            return ((float[]) array).length;
339
340        if (array instanceof double[])
341            return ((double[]) array).length;
342
343        if (array == null)
344            throw new NullPointerException();
345
346        throw new IllegalArgumentException("Not an array");
347    }
348
349    /**
350     * Returns the element of the array at the specified index, converted to a
351     * {@code long}, if possible. This reproduces the effect of {@code
352     * array[index]}
353     *
354     * @param array
355     *            the array
356     * @param index
357     *            the index
358     *
359     * @return the requested element
360     *
361     * @throws NullPointerException
362     *             if the {@code array} is {@code null}
363     * @throws IllegalArgumentException
364     *             if {@code array} is not an array or the element at the
365     *             index position can not be converted to the return type
366     * @throws ArrayIndexOutOfBoundsException
367     *             if {@code index < 0 || index >= array.length}
368     *
369     * @since Android 1.0
370     */
371    public static long getLong(Object array, int index)
372            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
373        if (array instanceof long[]) {
374            return ((long[]) array)[index];
375        } else {
376            return getInt(array, index);
377        }
378    }
379
380    /**
381     * Returns the element of the array at the specified index, converted to a
382     * {@code short}, if possible. This reproduces the effect of {@code
383     * array[index]}
384     *
385     * @param array
386     *            the array
387     * @param index
388     *            the index
389     *
390     * @return the requested element
391     *
392     * @throws NullPointerException
393     *             if the {@code array} is {@code null}
394     * @throws IllegalArgumentException
395     *             if {@code array} is not an array or the element at the
396     *             index position can not be converted to the return type
397     * @throws ArrayIndexOutOfBoundsException
398     *             if {@code index < 0 || index >= array.length}
399     *
400     * @since Android 1.0
401     */
402    public static short getShort(Object array, int index)
403            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
404        if (array instanceof short[])
405            return ((short[]) array)[index];
406
407        return getByte(array, index);
408    }
409
410    /**
411     * Returns a new multidimensional array of the specified component type and
412     * dimensions. This reproduces the effect of {@code new
413     * componentType[d0][d1]...[dn]} for a dimensions array of { d0, d1, ... ,
414     * dn }.
415     *
416     * @param componentType
417     *            the component type of the new array
418     * @param dimensions
419     *            the dimensions of the new array
420     *
421     * @return the new array
422     *
423     * @throws NullPointerException
424     *             if the component type is {@code null}
425     * @throws NegativeArraySizeException
426     *             if any of the dimensions are negative
427     * @throws IllegalArgumentException
428     *             if the array of dimensions is of size zero, or exceeds the
429     *             limit of the number of dimension for an array (currently 255)
430     *
431     * @since Android 1.0
432     */
433    public static Object newInstance(Class<?> componentType, int[] dimensions)
434            throws NegativeArraySizeException, IllegalArgumentException {
435        if (dimensions.length <= 0 || dimensions.length > 255)
436            throw new IllegalArgumentException("Bad number of dimensions");
437
438        if (componentType == Void.TYPE)
439            throw new IllegalArgumentException();
440
441        if (componentType == null)
442            throw new NullPointerException();
443
444        return createMultiArray(componentType, dimensions);
445    }
446
447    /*
448     * Create a multi-dimensional array of objects with the specified type.
449     */
450    native private static Object createMultiArray(Class<?> componentType,
451        int[] dimensions) throws NegativeArraySizeException;
452
453    /**
454     * Returns a new array of the specified component type and length. This
455     * reproduces the effect of {@code new componentType[size]}.
456     *
457     * @param componentType
458     *            the component type of the new array
459     * @param size
460     *            the length of the new array
461     *
462     * @return the new array
463     *
464     * @throws NullPointerException
465     *             if the component type is null
466     * @throws NegativeArraySizeException
467     *             if {@code size < 0}
468     *
469     * @since Android 1.0
470     */
471    public static Object newInstance(Class<?> componentType, int size)
472            throws NegativeArraySizeException {
473        if (!componentType.isPrimitive())
474            return createObjectArray(componentType, size);
475
476        if (componentType == Boolean.TYPE)
477            return new boolean[size];
478
479        if (componentType == Byte.TYPE)
480            return new byte[size];
481
482        if (componentType == Character.TYPE)
483            return new char[size];
484
485        if (componentType == Short.TYPE)
486            return new short[size];
487
488        if (componentType == Integer.TYPE)
489            return new int[size];
490
491        if (componentType == Long.TYPE)
492            return new long[size];
493
494        if (componentType == Float.TYPE)
495            return new float[size];
496
497        if (componentType == Double.TYPE)
498            return new double[size];
499
500        if (componentType == Void.TYPE)
501            throw new IllegalArgumentException();
502
503        throw new RuntimeException(); // should be impossible
504    }
505
506    /*
507     * Create a one-dimensional array of objects with the specified type.
508     */
509    native private static Object createObjectArray(Class<?> componentType,
510        int length) throws NegativeArraySizeException;
511
512    /**
513     * Sets the element of the array at the specified index to the value. This
514     * reproduces the effect of {@code array[index] = value}. If the array
515     * component is a primitive type, the value is automatically unwrapped.
516     *
517     * @param array
518     *            the array
519     * @param index
520     *            the index
521     * @param value
522     *            the new value
523     *
524     * @throws NullPointerException
525     *             if the {@code array} is {@code null}
526     * @throws IllegalArgumentException
527     *             if {@code array} is not an array or the value cannot be
528     *             converted to the array type by a widening conversion
529     * @throws ArrayIndexOutOfBoundsException
530     *             if {@code  index < 0 || index >= array.length}
531     *
532     * @since Android 1.0
533     */
534    public static void set(Object array, int index, Object value)
535            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
536        if (!array.getClass().isArray()) {
537            throw new IllegalArgumentException("Not an array type");
538        }
539
540        if (array instanceof Object[]) {
541            if (value != null &&
542                !array.getClass().getComponentType().isInstance(value)) {
543                // incompatible object type for this array
544                throw new IllegalArgumentException("Wrong array type");
545            }
546
547            ((Object[]) array)[index] = value;
548        } else {
549            if (value == null) {
550                throw new IllegalArgumentException("Primitive array can't take null values.");
551            }
552
553            if (value instanceof Boolean)
554                setBoolean(array, index, ((Boolean) value).booleanValue());
555            else if (value instanceof Byte)
556                setByte(array, index, ((Byte) value).byteValue());
557            else if (value instanceof Character)
558                setChar(array, index, ((Character) value).charValue());
559            else if (value instanceof Short)
560                setShort(array, index, ((Short) value).shortValue());
561            else if (value instanceof Integer)
562                setInt(array, index, ((Integer) value).intValue());
563            else if (value instanceof Long)
564                setLong(array, index, ((Long) value).longValue());
565            else if (value instanceof Float)
566                setFloat(array, index, ((Float) value).floatValue());
567            else if (value instanceof Double)
568                setDouble(array, index, ((Double) value).doubleValue());
569        }
570    }
571
572    /**
573     * Sets the element of the array at the specified index to the {@code
574     * boolean} value. This reproduces the effect of {@code array[index] =
575     * value}.
576     *
577     * @param array
578     *            the array
579     * @param index
580     *            the index
581     * @param value
582     *            the new value
583     *
584     * @throws NullPointerException
585     *             if the {@code array} is {@code null}
586     * @throws IllegalArgumentException
587     *             if the {@code array} is not an array or the value cannot be
588     *             converted to the array type by a widening conversion
589     * @throws ArrayIndexOutOfBoundsException
590     *             if {@code  index < 0 || index >= array.length}
591     *
592     * @since Android 1.0
593     */
594    public static void setBoolean(Object array, int index, boolean value) {
595        if (array instanceof boolean[]) {
596            ((boolean[]) array)[index] = value;
597        } else {
598            setByte(array, index, value ? (byte)1 : (byte)0);
599        }
600    }
601
602    /**
603     * Sets the element of the array at the specified index to the {@code byte}
604     * value. This reproduces the effect of {@code array[index] = value}.
605     *
606     * @param array
607     *            the array
608     * @param index
609     *            the index
610     * @param value
611     *            the new value
612     *
613     * @throws NullPointerException
614     *             if the {@code array} is {@code null}
615     * @throws IllegalArgumentException
616     *             if the {@code array} is not an array or the value cannot be
617     *             converted to the array type by a widening conversion
618     * @throws ArrayIndexOutOfBoundsException
619     *             if {@code  index < 0 || index >= array.length}
620     *
621     * @since Android 1.0
622     */
623    public static void setByte(Object array, int index, byte value)
624            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
625        if (array instanceof byte[]) {
626            ((byte[]) array)[index] = value;
627        } else {
628            setShort(array, index, value);
629        }
630    }
631
632    /**
633     * Set the element of the array at the specified index to the {@code char}
634     * value. This reproduces the effect of {@code array[index] = value}.
635     *
636     * @param array
637     *            the array
638     * @param index
639     *            the index
640     * @param value
641     *            the new value
642     *
643     * @throws NullPointerException
644     *             if the {@code array} is {@code null}
645     * @throws IllegalArgumentException
646     *             if the {@code array} is not an array or the value cannot be
647     *             converted to the array type by a widening conversion
648     * @throws ArrayIndexOutOfBoundsException
649     *             if {@code  index < 0 || index >= array.length}
650     *
651     * @since Android 1.0
652     */
653    public static void setChar(Object array, int index, char value)
654            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
655        if (array instanceof char[]) {
656            ((char[]) array)[index] = value;
657        } else if (array == null) {
658            throw new NullPointerException();
659        } else if (!array.getClass().isArray()) {
660            throw new IllegalArgumentException("Not an array");
661        } else {
662            throw new IllegalArgumentException("Wrong array type");
663        }
664    }
665
666    /**
667     * Set the element of the array at the specified index to the {@code double}
668     * value. This reproduces the effect of {@code array[index] = value}.
669     *
670     * @param array
671     *            the array
672     * @param index
673     *            the index
674     * @param value
675     *            the new value
676     *
677     * @throws NullPointerException
678     *             if the {@code array} is {@code null}
679     * @throws IllegalArgumentException
680     *             if the {@code array} is not an array or the value cannot be
681     *             converted to the array type by a widening conversion
682     * @throws ArrayIndexOutOfBoundsException
683     *             if {@code  index < 0 || index >= array.length}
684     *
685     * @since Android 1.0
686     */
687    public static void setDouble(Object array, int index, double value)
688            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
689        if (array instanceof double[]) {
690            ((double[]) array)[index] = value;
691        } else if (array == null) {
692            throw new NullPointerException();
693        } else if (!array.getClass().isArray()) {
694            throw new IllegalArgumentException("Not an array");
695        } else {
696            throw new IllegalArgumentException("Wrong array type");
697        }
698    }
699
700    /**
701     * Set the element of the array at the specified index to the {@code float}
702     * value. This reproduces the effect of {@code array[index] = value}.
703     *
704     * @param array
705     *            the array
706     * @param index
707     *            the index
708     * @param value
709     *            the new value
710     *
711     * @throws NullPointerException
712     *             if the {@code array} is {@code null}
713     * @throws IllegalArgumentException
714     *             if the {@code array} is not an array or the value cannot be
715     *             converted to the array type by a widening conversion
716     * @throws ArrayIndexOutOfBoundsException
717     *             if {@code  index < 0 || index >= array.length}
718     *
719     * @since Android 1.0
720     */
721    public static void setFloat(Object array, int index, float value)
722            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
723        if (array instanceof float[]) {
724            ((float[]) array)[index] = value;
725        } else {
726            setDouble(array, index, value);
727        }
728    }
729
730    /**
731     * Set the element of the array at the specified index to the {@code int}
732     * value. This reproduces the effect of {@code array[index] = value}.
733     *
734     * @param array
735     *            the array
736     * @param index
737     *            the index
738     * @param value
739     *            the new value
740     *
741     * @throws NullPointerException
742     *             if the {@code array} is {@code null}
743     * @throws IllegalArgumentException
744     *             if the {@code array} is not an array or the value cannot be
745     *             converted to the array type by a widening conversion
746     * @throws ArrayIndexOutOfBoundsException
747     *             if {@code  index < 0 || index >= array.length}
748     *
749     * @since Android 1.0
750     */
751    public static void setInt(Object array, int index, int value)
752            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
753        if (array instanceof int[]) {
754            ((int[]) array)[index] = value;
755        } else {
756            setLong(array, index, value);
757        }
758    }
759
760    /**
761     * Set the element of the array at the specified index to the {@code long}
762     * value. This reproduces the effect of {@code array[index] = value}.
763     *
764     * @param array
765     *            the array
766     * @param index
767     *            the index
768     * @param value
769     *            the new value
770     *
771     * @throws NullPointerException
772     *             if the {@code array} is {@code null}
773     * @throws IllegalArgumentException
774     *             if the {@code array} is not an array or the value cannot be
775     *             converted to the array type by a widening conversion
776     * @throws ArrayIndexOutOfBoundsException
777     *             if {@code  index < 0 || index >= array.length}
778     *
779     * @since Android 1.0
780     */
781    public static void setLong(Object array, int index, long value)
782            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
783        if (array instanceof long[]) {
784            ((long[]) array)[index] = value;
785        } else {
786            setFloat(array, index, value);
787        }
788    }
789
790    /**
791     * Set the element of the array at the specified index to the {@code short}
792     * value. This reproduces the effect of {@code array[index] = value}.
793     *
794     * @param array
795     *            the array
796     * @param index
797     *            the index
798     * @param value
799     *            the new value
800     *
801     * @throws NullPointerException
802     *             if the {@code array} is {@code null}
803     * @throws IllegalArgumentException
804     *             if the {@code array} is not an array or the value cannot be
805     *             converted to the array type by a widening conversion
806     * @throws ArrayIndexOutOfBoundsException
807     *             if {@code  index < 0 || index >= array.length}
808     *
809     * @since Android 1.0
810     */
811    public static void setShort(Object array, int index, short value)
812            throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
813        if (array instanceof short[]) {
814            ((short[]) array)[index] = value;
815        } else {
816            setInt(array, index, value);
817        }
818    }
819
820}
821