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 * Provides static methods to create and access arrays dynamically.
37 */
38public final class Array {
39    private Array() {
40    }
41
42    private static IllegalArgumentException notAnArray(Object o) {
43        throw new IllegalArgumentException("Not an array: " + o.getClass());
44    }
45
46    private static IllegalArgumentException incompatibleType(Object o) {
47        throw new IllegalArgumentException("Array has incompatible type: " + o.getClass());
48    }
49
50    private static RuntimeException badArray(Object array) {
51        if (array == null) {
52            throw new NullPointerException("array == null");
53        } else if (!array.getClass().isArray()) {
54            throw notAnArray(array);
55        } else {
56            throw incompatibleType(array);
57        }
58    }
59
60    /**
61     * Returns the element of the array at the specified index. Equivalent to {@code array[index]}.
62     * If the array component is a primitive type, the result is automatically boxed.
63     *
64     * @throws NullPointerException if {@code array == null}
65     * @throws IllegalArgumentException
66     *             if {@code array} is not an array
67     * @throws ArrayIndexOutOfBoundsException
68     *             if {@code  index < 0 || index >= array.length}
69     */
70    public static Object get(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
71        if (array instanceof Object[]) {
72            return ((Object[]) array)[index];
73        }
74        if (array instanceof boolean[]) {
75            return ((boolean[]) array)[index] ? Boolean.TRUE : Boolean.FALSE;
76        }
77        if (array instanceof byte[]) {
78            return Byte.valueOf(((byte[]) array)[index]);
79        }
80        if (array instanceof char[]) {
81            return Character.valueOf(((char[]) array)[index]);
82        }
83        if (array instanceof short[]) {
84            return Short.valueOf(((short[]) array)[index]);
85        }
86        if (array instanceof int[]) {
87            return Integer.valueOf(((int[]) array)[index]);
88        }
89        if (array instanceof long[]) {
90            return Long.valueOf(((long[]) array)[index]);
91        }
92        if (array instanceof float[]) {
93            return new Float(((float[]) array)[index]);
94        }
95        if (array instanceof double[]) {
96            return new Double(((double[]) array)[index]);
97        }
98        if (array == null) {
99            throw new NullPointerException("array == null");
100        }
101        throw notAnArray(array);
102    }
103
104    /**
105     * Returns the boolean at the given index in the given boolean array.
106     *
107     * @throws NullPointerException if {@code array == null}
108     * @throws IllegalArgumentException
109     *             if {@code array} is not an array or the element at the
110     *             index position can not be converted to the return type
111     * @throws ArrayIndexOutOfBoundsException
112     *             if {@code index < 0 || index >= array.length}
113     */
114    public static boolean getBoolean(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
115        if (array instanceof boolean[]) {
116            return ((boolean[]) array)[index];
117        }
118        throw badArray(array);
119    }
120
121    /**
122     * Returns the byte at the given index in the given byte array.
123     *
124     * @throws NullPointerException if {@code array == null}
125     * @throws IllegalArgumentException
126     *             if {@code array} is not an array or the element at the
127     *             index position can not be converted to the return type
128     * @throws ArrayIndexOutOfBoundsException
129     *             if {@code index < 0 || index >= array.length}
130     */
131    public static byte getByte(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
132        if (array instanceof byte[]) {
133            return ((byte[]) array)[index];
134        }
135        throw badArray(array);
136    }
137
138    /**
139     * Returns the char at the given index in the given char array.
140     *
141     * @throws NullPointerException if {@code array == null}
142     * @throws IllegalArgumentException
143     *             if {@code array} is not an array or the element at the
144     *             index position can not be converted to the return type
145     * @throws ArrayIndexOutOfBoundsException
146     *             if {@code index < 0 || index >= array.length}
147     */
148    public static char getChar(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
149        if (array instanceof char[]) {
150            return ((char[]) array)[index];
151        }
152        throw badArray(array);
153    }
154
155    /**
156     * Returns the double at the given index in the given array.
157     * Applies to byte, char, float, double, int, long, and short arrays.
158     *
159     * @throws NullPointerException if {@code array == null}
160     * @throws IllegalArgumentException
161     *             if {@code array} is not an array or the element at the
162     *             index position can not be converted to the return type
163     * @throws ArrayIndexOutOfBoundsException
164     *             if {@code index < 0 || index >= array.length}
165     */
166    public static double getDouble(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
167        if (array instanceof double[]) {
168            return ((double[]) array)[index];
169        } else if (array instanceof byte[]) {
170            return ((byte[]) array)[index];
171        } else if (array instanceof char[]) {
172            return ((char[]) array)[index];
173        } else if (array instanceof float[]) {
174            return ((float[]) array)[index];
175        } else if (array instanceof int[]) {
176            return ((int[]) array)[index];
177        } else if (array instanceof long[]) {
178            return ((long[]) array)[index];
179        } else if (array instanceof short[]) {
180            return ((short[]) array)[index];
181        }
182        throw badArray(array);
183    }
184
185    /**
186     * Returns the float at the given index in the given array.
187     * Applies to byte, char, float, int, long, and short arrays.
188     *
189     * @throws NullPointerException if {@code array == null}
190     * @throws IllegalArgumentException
191     *             if {@code array} is not an array or the element at the
192     *             index position can not be converted to the return type
193     * @throws ArrayIndexOutOfBoundsException
194     *             if {@code index < 0 || index >= array.length}
195     */
196    public static float getFloat(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
197        if (array instanceof float[]) {
198            return ((float[]) array)[index];
199        } else if (array instanceof byte[]) {
200            return ((byte[]) array)[index];
201        } else if (array instanceof char[]) {
202            return ((char[]) array)[index];
203        } else if (array instanceof int[]) {
204            return ((int[]) array)[index];
205        } else if (array instanceof long[]) {
206            return ((long[]) array)[index];
207        } else if (array instanceof short[]) {
208            return ((short[]) array)[index];
209        }
210        throw badArray(array);
211    }
212
213    /**
214     * Returns the int at the given index in the given array.
215     * Applies to byte, char, int, and short arrays.
216     *
217     * @throws NullPointerException if {@code array == null}
218     * @throws IllegalArgumentException
219     *             if {@code array} is not an array or the element at the
220     *             index position can not be converted to the return type
221     * @throws ArrayIndexOutOfBoundsException
222     *             if {@code index < 0 || index >= array.length}
223     */
224    public static int getInt(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
225        if (array instanceof int[]) {
226            return ((int[]) array)[index];
227        } else if (array instanceof byte[]) {
228            return ((byte[]) array)[index];
229        } else if (array instanceof char[]) {
230            return ((char[]) array)[index];
231        } else if (array instanceof short[]) {
232            return ((short[]) array)[index];
233        }
234        throw badArray(array);
235    }
236
237    /**
238     * Returns the length of the array. Equivalent to {@code array.length}.
239     *
240     * @throws NullPointerException if {@code array == null}
241     * @throws IllegalArgumentException
242     *             if {@code array} is not an array
243     */
244    public static int getLength(Object array) {
245        if (array instanceof Object[]) {
246            return ((Object[]) array).length;
247        } else if (array instanceof boolean[]) {
248            return ((boolean[]) array).length;
249        } else if (array instanceof byte[]) {
250            return ((byte[]) array).length;
251        } else if (array instanceof char[]) {
252            return ((char[]) array).length;
253        } else if (array instanceof double[]) {
254            return ((double[]) array).length;
255        } else if (array instanceof float[]) {
256            return ((float[]) array).length;
257        } else if (array instanceof int[]) {
258            return ((int[]) array).length;
259        } else if (array instanceof long[]) {
260            return ((long[]) array).length;
261        } else if (array instanceof short[]) {
262            return ((short[]) array).length;
263        }
264        throw badArray(array);
265      }
266
267    /**
268     * Returns the long at the given index in the given array.
269     * Applies to byte, char, int, long, and short arrays.
270     *
271     * @throws NullPointerException if {@code array == null}
272     * @throws IllegalArgumentException
273     *             if {@code array} is not an array or the element at the
274     *             index position can not be converted to the return type
275     * @throws ArrayIndexOutOfBoundsException
276     *             if {@code index < 0 || index >= array.length}
277     */
278    public static long getLong(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
279        if (array instanceof long[]) {
280            return ((long[]) array)[index];
281        } else if (array instanceof byte[]) {
282            return ((byte[]) array)[index];
283        } else if (array instanceof char[]) {
284            return ((char[]) array)[index];
285        } else if (array instanceof int[]) {
286            return ((int[]) array)[index];
287        } else if (array instanceof short[]) {
288            return ((short[]) array)[index];
289        }
290        throw badArray(array);
291    }
292
293    /**
294     * Returns the short at the given index in the given array.
295     * Applies to byte and short arrays.
296     *
297     * @throws NullPointerException if {@code array == null}
298     * @throws IllegalArgumentException
299     *             if {@code array} is not an array or the element at the
300     *             index position can not be converted to the return type
301     * @throws ArrayIndexOutOfBoundsException
302     *             if {@code index < 0 || index >= array.length}
303     */
304    public static short getShort(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
305        if (array instanceof short[]) {
306            return ((short[]) array)[index];
307        } else if (array instanceof byte[]) {
308            return ((byte[]) array)[index];
309        }
310        throw badArray(array);
311    }
312
313    /**
314     * Returns a new multidimensional array of the specified component type and
315     * dimensions. Equivalent to {@code new componentType[d0][d1]...[dn]} for a
316     * dimensions array of { d0, d1, ... , dn }.
317     *
318     * @throws NullPointerException if {@code array == null}
319     * @throws NegativeArraySizeException
320     *             if any of the dimensions are negative
321     * @throws IllegalArgumentException
322     *             if the array of dimensions is of size zero, or exceeds the
323     *             limit of the number of dimension for an array (currently 255)
324     */
325    public static Object newInstance(Class<?> componentType, int... dimensions) throws NegativeArraySizeException, IllegalArgumentException {
326        if (dimensions.length <= 0 || dimensions.length > 255) {
327            throw new IllegalArgumentException("Bad number of dimensions: " + dimensions.length);
328        }
329        if (componentType == void.class) {
330            throw new IllegalArgumentException("Can't allocate an array of void");
331        }
332        if (componentType == null) {
333            throw new NullPointerException("componentType == null");
334        }
335        return createMultiArray(componentType, dimensions);
336    }
337
338    /*
339     * Create a multi-dimensional array of objects with the specified type.
340     */
341    private static native Object createMultiArray(Class<?> componentType, int[] dimensions) throws NegativeArraySizeException;
342
343    /**
344     * Returns a new array of the specified component type and length.
345     * Equivalent to {@code new componentType[size]}.
346     *
347     * @throws NullPointerException
348     *             if the component type is null
349     * @throws NegativeArraySizeException
350     *             if {@code size < 0}
351     */
352    public static Object newInstance(Class<?> componentType, int size) throws NegativeArraySizeException {
353        if (!componentType.isPrimitive()) {
354            return createObjectArray(componentType, size);
355        } else if (componentType == boolean.class) {
356            return new boolean[size];
357        } else if (componentType == byte.class) {
358            return new byte[size];
359        } else if (componentType == char.class) {
360            return new char[size];
361        } else if (componentType == short.class) {
362            return new short[size];
363        } else if (componentType == int.class) {
364            return new int[size];
365        } else if (componentType == long.class) {
366            return new long[size];
367        } else if (componentType == float.class) {
368            return new float[size];
369        } else if (componentType == double.class) {
370            return new double[size];
371        } else if (componentType == void.class) {
372            throw new IllegalArgumentException("Can't allocate an array of void");
373        }
374        throw new AssertionError();
375    }
376
377    /*
378     * Create a one-dimensional array of objects with the specified type.
379     */
380    private static native Object createObjectArray(Class<?> componentType, int length) throws NegativeArraySizeException;
381
382    /**
383     * Sets the element of the array at the specified index to the value.
384     * Equivalent to {@code array[index] = value}. If the array
385     * component is a primitive type, the value is automatically unboxed.
386     *
387     * @throws NullPointerException if {@code array == null}
388     * @throws IllegalArgumentException
389     *             if {@code array} is not an array or the value cannot be
390     *             converted to the array type by a widening conversion
391     * @throws ArrayIndexOutOfBoundsException
392     *             if {@code  index < 0 || index >= array.length}
393     */
394    public static void set(Object array, int index, Object value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
395        if (!array.getClass().isArray()) {
396            throw notAnArray(array);
397        }
398
399        if (array instanceof Object[]) {
400            if (value != null && !array.getClass().getComponentType().isInstance(value)) {
401                throw incompatibleType(array);
402            }
403            ((Object[]) array)[index] = value;
404        } else {
405            if (value == null) {
406                throw new IllegalArgumentException("Primitive array can't take null values.");
407            }
408            if (value instanceof Boolean) {
409                setBoolean(array, index, ((Boolean) value).booleanValue());
410            } else if (value instanceof Byte) {
411                setByte(array, index, ((Byte) value).byteValue());
412            } else if (value instanceof Character) {
413                setChar(array, index, ((Character) value).charValue());
414            } else if (value instanceof Short) {
415                setShort(array, index, ((Short) value).shortValue());
416            } else if (value instanceof Integer) {
417                setInt(array, index, ((Integer) value).intValue());
418            } else if (value instanceof Long) {
419                setLong(array, index, ((Long) value).longValue());
420            } else if (value instanceof Float) {
421                setFloat(array, index, ((Float) value).floatValue());
422            } else if (value instanceof Double) {
423                setDouble(array, index, ((Double) value).doubleValue());
424            }
425        }
426    }
427
428    /**
429     * Sets {@code array[index] = value}. Applies to boolean arrays.
430     *
431     * @throws NullPointerException if {@code array == null}
432     * @throws IllegalArgumentException
433     *             if the {@code array} is not an array or the value cannot be
434     *             converted to the array type by a widening conversion
435     * @throws ArrayIndexOutOfBoundsException
436     *             if {@code  index < 0 || index >= array.length}
437     */
438    public static void setBoolean(Object array, int index, boolean value) {
439        if (array instanceof boolean[]) {
440            ((boolean[]) array)[index] = value;
441        } else {
442            throw badArray(array);
443        }
444    }
445
446    /**
447     * Sets {@code array[index] = value}. Applies to byte, double, float, int, long, and short arrays.
448     *
449     * @throws NullPointerException if {@code array == null}
450     * @throws IllegalArgumentException
451     *             if the {@code array} is not an array or the value cannot be
452     *             converted to the array type by a widening conversion
453     * @throws ArrayIndexOutOfBoundsException
454     *             if {@code  index < 0 || index >= array.length}
455     */
456    public static void setByte(Object array, int index, byte value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
457        if (array instanceof byte[]) {
458            ((byte[]) array)[index] = value;
459        } else if (array instanceof double[]) {
460            ((double[]) array)[index] = value;
461        } else if (array instanceof float[]) {
462            ((float[]) array)[index] = value;
463        } else if (array instanceof int[]) {
464            ((int[]) array)[index] = value;
465        } else if (array instanceof long[]) {
466            ((long[]) array)[index] = value;
467        } else if (array instanceof short[]) {
468            ((short[]) array)[index] = value;
469        } else {
470            throw badArray(array);
471        }
472    }
473
474    /**
475     * Sets {@code array[index] = value}. Applies to char, double, float, int, and long arrays.
476     *
477     * @throws NullPointerException if {@code array == null}
478     * @throws IllegalArgumentException
479     *             if the {@code array} is not an array or the value cannot be
480     *             converted to the array type by a widening conversion
481     * @throws ArrayIndexOutOfBoundsException
482     *             if {@code  index < 0 || index >= array.length}
483     */
484    public static void setChar(Object array, int index, char value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
485        if (array instanceof char[]) {
486            ((char[]) array)[index] = value;
487        } else if (array instanceof double[]) {
488            ((double[]) array)[index] = value;
489        } else if (array instanceof float[]) {
490            ((float[]) array)[index] = value;
491        } else if (array instanceof int[]) {
492            ((int[]) array)[index] = value;
493        } else if (array instanceof long[]) {
494            ((long[]) array)[index] = value;
495        } else {
496            throw badArray(array);
497        }
498    }
499
500    /**
501     * Sets {@code array[index] = value}. Applies to double arrays.
502     *
503     * @throws NullPointerException if {@code array == null}
504     * @throws IllegalArgumentException
505     *             if the {@code array} is not an array or the value cannot be
506     *             converted to the array type by a widening conversion
507     * @throws ArrayIndexOutOfBoundsException
508     *             if {@code  index < 0 || index >= array.length}
509     */
510    public static void setDouble(Object array, int index, double value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
511        if (array instanceof double[]) {
512            ((double[]) array)[index] = value;
513        } else {
514            throw badArray(array);
515        }
516    }
517
518    /**
519     * Sets {@code array[index] = value}. Applies to double and float arrays.
520     *
521     * @throws NullPointerException if {@code array == null}
522     * @throws IllegalArgumentException
523     *             if the {@code array} is not an array or the value cannot be
524     *             converted to the array type by a widening conversion
525     * @throws ArrayIndexOutOfBoundsException
526     *             if {@code  index < 0 || index >= array.length}
527     */
528    public static void setFloat(Object array, int index, float value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
529        if (array instanceof float[]) {
530            ((float[]) array)[index] = value;
531        } else if (array instanceof double[]) {
532            ((double[]) array)[index] = value;
533        } else {
534            throw badArray(array);
535        }
536    }
537
538    /**
539     * Sets {@code array[index] = value}. Applies to double, float, int, and long arrays.
540     *
541     * @throws NullPointerException if {@code array == null}
542     * @throws IllegalArgumentException
543     *             if the {@code array} is not an array or the value cannot be
544     *             converted to the array type by a widening conversion
545     * @throws ArrayIndexOutOfBoundsException
546     *             if {@code  index < 0 || index >= array.length}
547     */
548    public static void setInt(Object array, int index, int value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
549        if (array instanceof int[]) {
550            ((int[]) array)[index] = value;
551        } else if (array instanceof double[]) {
552            ((double[]) array)[index] = value;
553        } else if (array instanceof float[]) {
554            ((float[]) array)[index] = value;
555        } else if (array instanceof long[]) {
556            ((long[]) array)[index] = value;
557        } else {
558            throw badArray(array);
559        }
560    }
561
562    /**
563     * Sets {@code array[index] = value}. Applies to double, float, and long arrays.
564     *
565     * @throws NullPointerException if {@code array == null}
566     * @throws IllegalArgumentException
567     *             if the {@code array} is not an array or the value cannot be
568     *             converted to the array type by a widening conversion
569     * @throws ArrayIndexOutOfBoundsException
570     *             if {@code  index < 0 || index >= array.length}
571     */
572    public static void setLong(Object array, int index, long value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
573        if (array instanceof long[]) {
574            ((long[]) array)[index] = value;
575        } else if (array instanceof double[]) {
576            ((double[]) array)[index] = value;
577        } else if (array instanceof float[]) {
578            ((float[]) array)[index] = value;
579        } else {
580            throw badArray(array);
581        }
582    }
583
584    /**
585     * Sets {@code array[index] = value}. Applies to double, float, int, long, and short arrays.
586     *
587     * @throws NullPointerException if {@code array == null}
588     * @throws IllegalArgumentException
589     *             if the {@code array} is not an array or the value cannot be
590     *             converted to the array type by a widening conversion
591     * @throws ArrayIndexOutOfBoundsException
592     *             if {@code  index < 0 || index >= array.length}
593     */
594    public static void setShort(Object array, int index, short value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
595        if (array instanceof short[]) {
596            ((short[]) array)[index] = value;
597        } else if (array instanceof double[]) {
598            ((double[]) array)[index] = value;
599        } else if (array instanceof float[]) {
600            ((float[]) array)[index] = value;
601        } else if (array instanceof int[]) {
602            ((int[]) array)[index] = value;
603        } else if (array instanceof long[]) {
604            ((long[]) array)[index] = value;
605        } else {
606            throw badArray(array);
607        }
608    }
609}
610