1 /*
  2  * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package java.lang.reflect;
 27 
 28 import java.util.Objects;
 29 import jdk.internal.vm.annotation.IntrinsicCandidate;
 30 
 31 /**
 32  * The {@code Array} class provides static methods to dynamically create and
 33  * access Java arrays.
 34  *
 35  * <p>{@code Array} permits widening conversions to occur during a get or set
 36  * operation, but throws an {@code IllegalArgumentException} if a narrowing
 37  * conversion would occur.
 38  *
 39  * @author Nakul Saraiya
 40  * @since 1.1
 41  */
 42 public final
 43 class Array {
 44 
 45     /**
 46      * Constructor.  Class Array is not instantiable.
 47      */
 48     private Array() {}
 49 
 50     /**
 51      * Creates a new array with the specified component type and
 52      * length.
 53      * Invoking this method is equivalent to creating an array
 54      * as follows:
 55      * <blockquote>
 56      * <pre>
 57      * int[] x = {length};
 58      * Array.newInstance(componentType, x);
 59      * </pre>
 60      * </blockquote>
 61      *
 62      * <p>The number of dimensions of the new array must not
 63      * exceed 255.
 64      *
 65      * @param  componentType the {@code Class} object representing the
 66      *         component type of the new array
 67      * @param  length the length of the new array
 68      * @return the new array
 69      * @throws NullPointerException if the specified
 70      *         {@code componentType} parameter is null
 71      * @throws IllegalArgumentException if componentType is {@link
 72      *         Void#TYPE} or if the number of dimensions of the requested array
 73      *         instance exceed 255.
 74      * @throws NegativeArraySizeException if the specified {@code length}
 75      *         is negative
 76      */
 77     public static Object newInstance(Class<?> componentType, int length)
 78         throws NegativeArraySizeException {
 79         return newArray(componentType, length);
 80     }
 81 
 82     /**
 83      * Creates a new array
 84      * with the specified component type and dimensions.
 85      * If {@code componentType}
 86      * represents a non-array class or interface, the new array
 87      * has {@code dimensions.length} dimensions and
 88      * {@code componentType} as its component type. If
 89      * {@code componentType} represents an array class, the
 90      * number of dimensions of the new array is equal to the sum
 91      * of {@code dimensions.length} and the number of
 92      * dimensions of {@code componentType}. In this case, the
 93      * component type of the new array is the component type of
 94      * {@code componentType}.
 95      *
 96      * <p>The number of dimensions of the new array must not
 97      * exceed 255.
 98      *
 99      * @param componentType the {@code Class} object representing the component
100      * type of the new array
101      * @param dimensions an array of {@code int} representing the dimensions of
102      * the new array
103      * @return the new array
104      * @throws    NullPointerException if the specified
105      * {@code componentType} argument is null
106      * @throws    IllegalArgumentException if the specified {@code dimensions}
107      * argument is a zero-dimensional array, if componentType is {@link
108      * Void#TYPE}, or if the number of dimensions of the requested array
109      * instance exceed 255.
110      * @throws    NegativeArraySizeException if any of the components in
111      * the specified {@code dimensions} argument is negative.
112      */
113     public static Object newInstance(Class<?> componentType, int... dimensions)
114         throws IllegalArgumentException, NegativeArraySizeException {
115         return multiNewArray(componentType, dimensions);
116     }
117 
118     /**
119      * Returns the length of the specified array object, as an {@code int}.
120      *
121      * @param array the array
122      * @return the length of the array
123      * @throws    IllegalArgumentException if the object argument is not
124      * an array
125      */
126     @IntrinsicCandidate
127     public static native int getLength(Object array)
128         throws IllegalArgumentException;
129 
130     /**
131      * Returns the value of the indexed component in the specified
132      * array object.  The value is automatically wrapped in an object
133      * if it has a primitive type.
134      *
135      * @param array the array
136      * @param index the index
137      * @return the (possibly wrapped) value of the indexed component in
138      * the specified array
139      * @throws    NullPointerException If the specified object is null
140      * @throws    IllegalArgumentException If the specified object is not
141      * an array
142      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
143      * argument is negative, or if it is greater than or equal to the
144      * length of the specified array
145      */
146     public static Object get(Object array, int index)
147         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
148         Class<?> componentType = array.getClass().getComponentType();
149         if (componentType != null && !componentType.isPrimitive()) {
150             Object[] objArray = (Object[]) array.getClass().cast(array);
151             return objArray[index];
152         } else {
153             return getReferenceOrPrimitive(array, index);
154         }
155     }
156 
157     private static native Object getReferenceOrPrimitive(Object array, int index);
158 
159     /**
160      * Returns the value of the indexed component in the specified
161      * array object, as a {@code boolean}.
162      *
163      * @param array the array
164      * @param index the index
165      * @return the value of the indexed component in the specified array
166      * @throws    NullPointerException If the specified object is null
167      * @throws    IllegalArgumentException If the specified object is not
168      * an array, or if the indexed element cannot be converted to the
169      * return type by an identity or widening conversion
170      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
171      * argument is negative, or if it is greater than or equal to the
172      * length of the specified array
173      * @see Array#get
174      */
175     public static native boolean getBoolean(Object array, int index)
176         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
177 
178     /**
179      * Returns the value of the indexed component in the specified
180      * array object, as a {@code byte}.
181      *
182      * @param array the array
183      * @param index the index
184      * @return the value of the indexed component in the specified array
185      * @throws    NullPointerException If the specified object is null
186      * @throws    IllegalArgumentException If the specified object is not
187      * an array, or if the indexed element cannot be converted to the
188      * return type by an identity or widening conversion
189      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
190      * argument is negative, or if it is greater than or equal to the
191      * length of the specified array
192      * @see Array#get
193      */
194     public static native byte getByte(Object array, int index)
195         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
196 
197     /**
198      * Returns the value of the indexed component in the specified
199      * array object, as a {@code char}.
200      *
201      * @param array the array
202      * @param index the index
203      * @return the value of the indexed component in the specified array
204      * @throws    NullPointerException If the specified object is null
205      * @throws    IllegalArgumentException If the specified object is not
206      * an array, or if the indexed element cannot be converted to the
207      * return type by an identity or widening conversion
208      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
209      * argument is negative, or if it is greater than or equal to the
210      * length of the specified array
211      * @see Array#get
212      */
213     public static native char getChar(Object array, int index)
214         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
215 
216     /**
217      * Returns the value of the indexed component in the specified
218      * array object, as a {@code short}.
219      *
220      * @param array the array
221      * @param index the index
222      * @return the value of the indexed component in the specified array
223      * @throws    NullPointerException If the specified object is null
224      * @throws    IllegalArgumentException If the specified object is not
225      * an array, or if the indexed element cannot be converted to the
226      * return type by an identity or widening conversion
227      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
228      * argument is negative, or if it is greater than or equal to the
229      * length of the specified array
230      * @see Array#get
231      */
232     public static native short getShort(Object array, int index)
233         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
234 
235     /**
236      * Returns the value of the indexed component in the specified
237      * array object, as an {@code int}.
238      *
239      * @param array the array
240      * @param index the index
241      * @return the value of the indexed component in the specified array
242      * @throws    NullPointerException If the specified object is null
243      * @throws    IllegalArgumentException If the specified object is not
244      * an array, or if the indexed element cannot be converted to the
245      * return type by an identity or widening conversion
246      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
247      * argument is negative, or if it is greater than or equal to the
248      * length of the specified array
249      * @see Array#get
250      */
251     public static native int getInt(Object array, int index)
252         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
253 
254     /**
255      * Returns the value of the indexed component in the specified
256      * array object, as a {@code long}.
257      *
258      * @param array the array
259      * @param index the index
260      * @return the value of the indexed component in the specified array
261      * @throws    NullPointerException If the specified object is null
262      * @throws    IllegalArgumentException If the specified object is not
263      * an array, or if the indexed element cannot be converted to the
264      * return type by an identity or widening conversion
265      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
266      * argument is negative, or if it is greater than or equal to the
267      * length of the specified array
268      * @see Array#get
269      */
270     public static native long getLong(Object array, int index)
271         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
272 
273     /**
274      * Returns the value of the indexed component in the specified
275      * array object, as a {@code float}.
276      *
277      * @param array the array
278      * @param index the index
279      * @return the value of the indexed component in the specified array
280      * @throws    NullPointerException If the specified object is null
281      * @throws    IllegalArgumentException If the specified object is not
282      * an array, or if the indexed element cannot be converted to the
283      * return type by an identity or widening conversion
284      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
285      * argument is negative, or if it is greater than or equal to the
286      * length of the specified array
287      * @see Array#get
288      */
289     public static native float getFloat(Object array, int index)
290         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
291 
292     /**
293      * Returns the value of the indexed component in the specified
294      * array object, as a {@code double}.
295      *
296      * @param array the array
297      * @param index the index
298      * @return the value of the indexed component in the specified array
299      * @throws    NullPointerException If the specified object is null
300      * @throws    IllegalArgumentException If the specified object is not
301      * an array, or if the indexed element cannot be converted to the
302      * return type by an identity or widening conversion
303      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
304      * argument is negative, or if it is greater than or equal to the
305      * length of the specified array
306      * @see Array#get
307      */
308     public static native double getDouble(Object array, int index)
309         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
310 
311     /**
312      * Sets the value of the indexed component of the specified array
313      * object to the specified new value.  The new value is first
314      * automatically unwrapped if the array has a primitive component
315      * type.
316      * @param array the array
317      * @param index the index into the array
318      * @param value the new value of the indexed component
319      * @throws    NullPointerException If the specified object argument
320      * is null
321      * @throws    IllegalArgumentException If the specified object argument
322      * is not an array, or if the array component type is primitive and
323      * an unwrapping conversion fails
324      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
325      * argument is negative, or if it is greater than or equal to
326      * the length of the specified array
327      */
328     public static void set(Object array, int index, Object value)
329         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
330         Class<?> componentType = array.getClass().getComponentType();
331         if (componentType != null && !componentType.isPrimitive()) {
332             Object[] objArray = (Object[]) array.getClass().cast(array);
333             objArray[index] = componentType.cast(value);
334         } else {
335             setReferenceOrPrimitive(array, index, value);
336         }
337     }
338 
339     private static native void setReferenceOrPrimitive(Object array, int index, Object value);
340 
341     /**
342      * Sets the value of the indexed component of the specified array
343      * object to the specified {@code boolean} value.
344      * @param array the array
345      * @param index the index into the array
346      * @param z the new value of the indexed component
347      * @throws    NullPointerException If the specified object argument
348      * is null
349      * @throws    IllegalArgumentException If the specified object argument
350      * is not an array, or if the specified value cannot be converted
351      * to the underlying array's component type by an identity or a
352      * primitive widening conversion
353      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
354      * argument is negative, or if it is greater than or equal to
355      * the length of the specified array
356      * @see Array#set
357      */
358     public static native void setBoolean(Object array, int index, boolean z)
359         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
360 
361     /**
362      * Sets the value of the indexed component of the specified array
363      * object to the specified {@code byte} value.
364      * @param array the array
365      * @param index the index into the array
366      * @param b the new value of the indexed component
367      * @throws    NullPointerException If the specified object argument
368      * is null
369      * @throws    IllegalArgumentException If the specified object argument
370      * is not an array, or if the specified value cannot be converted
371      * to the underlying array's component type by an identity or a
372      * primitive widening conversion
373      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
374      * argument is negative, or if it is greater than or equal to
375      * the length of the specified array
376      * @see Array#set
377      */
378     public static native void setByte(Object array, int index, byte b)
379         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
380 
381     /**
382      * Sets the value of the indexed component of the specified array
383      * object to the specified {@code char} value.
384      * @param array the array
385      * @param index the index into the array
386      * @param c the new value of the indexed component
387      * @throws    NullPointerException If the specified object argument
388      * is null
389      * @throws    IllegalArgumentException If the specified object argument
390      * is not an array, or if the specified value cannot be converted
391      * to the underlying array's component type by an identity or a
392      * primitive widening conversion
393      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
394      * argument is negative, or if it is greater than or equal to
395      * the length of the specified array
396      * @see Array#set
397      */
398     public static native void setChar(Object array, int index, char c)
399         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
400 
401     /**
402      * Sets the value of the indexed component of the specified array
403      * object to the specified {@code short} value.
404      * @param array the array
405      * @param index the index into the array
406      * @param s the new value of the indexed component
407      * @throws    NullPointerException If the specified object argument
408      * is null
409      * @throws    IllegalArgumentException If the specified object argument
410      * is not an array, or if the specified value cannot be converted
411      * to the underlying array's component type by an identity or a
412      * primitive widening conversion
413      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
414      * argument is negative, or if it is greater than or equal to
415      * the length of the specified array
416      * @see Array#set
417      */
418     public static native void setShort(Object array, int index, short s)
419         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
420 
421     /**
422      * Sets the value of the indexed component of the specified array
423      * object to the specified {@code int} value.
424      * @param array the array
425      * @param index the index into the array
426      * @param i the new value of the indexed component
427      * @throws    NullPointerException If the specified object argument
428      * is null
429      * @throws    IllegalArgumentException If the specified object argument
430      * is not an array, or if the specified value cannot be converted
431      * to the underlying array's component type by an identity or a
432      * primitive widening conversion
433      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
434      * argument is negative, or if it is greater than or equal to
435      * the length of the specified array
436      * @see Array#set
437      */
438     public static native void setInt(Object array, int index, int i)
439         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
440 
441     /**
442      * Sets the value of the indexed component of the specified array
443      * object to the specified {@code long} value.
444      * @param array the array
445      * @param index the index into the array
446      * @param l the new value of the indexed component
447      * @throws    NullPointerException If the specified object argument
448      * is null
449      * @throws    IllegalArgumentException If the specified object argument
450      * is not an array, or if the specified value cannot be converted
451      * to the underlying array's component type by an identity or a
452      * primitive widening conversion
453      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
454      * argument is negative, or if it is greater than or equal to
455      * the length of the specified array
456      * @see Array#set
457      */
458     public static native void setLong(Object array, int index, long l)
459         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
460 
461     /**
462      * Sets the value of the indexed component of the specified array
463      * object to the specified {@code float} value.
464      * @param array the array
465      * @param index the index into the array
466      * @param f the new value of the indexed component
467      * @throws    NullPointerException If the specified object argument
468      * is null
469      * @throws    IllegalArgumentException If the specified object argument
470      * is not an array, or if the specified value cannot be converted
471      * to the underlying array's component type by an identity or a
472      * primitive widening conversion
473      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
474      * argument is negative, or if it is greater than or equal to
475      * the length of the specified array
476      * @see Array#set
477      */
478     public static native void setFloat(Object array, int index, float f)
479         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
480 
481     /**
482      * Sets the value of the indexed component of the specified array
483      * object to the specified {@code double} value.
484      * @param array the array
485      * @param index the index into the array
486      * @param d the new value of the indexed component
487      * @throws    NullPointerException If the specified object argument
488      * is null
489      * @throws    IllegalArgumentException If the specified object argument
490      * is not an array, or if the specified value cannot be converted
491      * to the underlying array's component type by an identity or a
492      * primitive widening conversion
493      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
494      * argument is negative, or if it is greater than or equal to
495      * the length of the specified array
496      * @see Array#set
497      */
498     public static native void setDouble(Object array, int index, double d)
499         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
500 
501     /*
502      * Private
503      */
504 
505     @IntrinsicCandidate
506     private static native Object newArray(Class<?> componentType, int length)
507         throws NegativeArraySizeException;
508 
509     private static native Object multiNewArray(Class<?> componentType,
510         int[] dimensions)
511         throws IllegalArgumentException, NegativeArraySizeException;
512 
513 
514 }