1 /*
  2  * Copyright (c) 1996, 2023, 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      * @implSpec
 54      * Invoking this method is equivalent to creating an array
 55      * as follows:
 56      * <blockquote>
 57      * {@code Array.newInstance(componentType, new int[]{length});}
 58      * </blockquote>
 59      *
 60      * <p>The number of dimensions of the new array must not
 61      * exceed 255.
 62      *
 63      * @param  componentType the {@code Class} object representing the
 64      *         component type of the new array
 65      * @param  length the length of the new array
 66      * @return the new array
 67      * @throws NullPointerException if the specified
 68      *         {@code componentType} parameter is null
 69      * @throws IllegalArgumentException if componentType is {@link
 70      *         Void#TYPE} or if the number of dimensions of the requested array
 71      *         instance exceed 255.
 72      * @throws NegativeArraySizeException if the specified {@code length}
 73      *         is negative
 74      */
 75     public static Object newInstance(Class<?> componentType, int length)
 76         throws NegativeArraySizeException {
 77         return newArray(componentType, length);
 78     }
 79 
 80     /**
 81      * Creates a new array
 82      * with the specified component type and dimensions.
 83      * If {@code componentType}
 84      * represents a non-array class or interface, the new array
 85      * has {@code dimensions.length} dimensions and
 86      * {@code componentType} as its component type. If
 87      * {@code componentType} represents an array class, the
 88      * number of dimensions of the new array is equal to the sum
 89      * of {@code dimensions.length} and the number of
 90      * dimensions of {@code componentType}. In this case, the
 91      * component type of the new array is the component type of
 92      * {@code componentType}.
 93      *
 94      * <p>The number of dimensions of the new array must not
 95      * exceed 255.
 96      *
 97      * @param componentType the {@code Class} object representing the component
 98      * type of the new array
 99      * @param dimensions an array of {@code int} representing the dimensions of
100      * the new array
101      * @return the new array
102      * @throws    NullPointerException if the specified
103      * {@code componentType} argument is null
104      * @throws    IllegalArgumentException if the specified {@code dimensions}
105      * argument is a zero-dimensional array, if componentType is {@link
106      * Void#TYPE}, or if the number of dimensions of the requested array
107      * instance exceed 255.
108      * @throws    NegativeArraySizeException if any of the components in
109      * the specified {@code dimensions} argument is negative.
110      */
111     public static Object newInstance(Class<?> componentType, int... dimensions)
112         throws IllegalArgumentException, NegativeArraySizeException {
113         return multiNewArray(componentType, dimensions);
114     }
115 
116     /**
117      * Returns the length of the specified array object, as an {@code int}.
118      *
119      * @param array the array
120      * @return the length of the array
121      * @throws    IllegalArgumentException if the object argument is not
122      * an array
123      */
124     @IntrinsicCandidate
125     public static native int getLength(Object array)
126         throws IllegalArgumentException;
127 
128     /**
129      * Returns the value of the indexed component in the specified
130      * array object.  The value is automatically wrapped in an object
131      * if it has a primitive type.
132      *
133      * @param array the array
134      * @param index the index
135      * @return the (possibly wrapped) value of the indexed component in
136      * the specified array
137      * @throws    NullPointerException If the specified object is null
138      * @throws    IllegalArgumentException If the specified object is not
139      * an array
140      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
141      * argument is negative, or if it is greater than or equal to the
142      * length of the specified array
143      */
144     public static Object get(Object array, int index)
145         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
146         Class<?> componentType = array.getClass().getComponentType();
147         if (componentType != null && !componentType.isPrimitive()) {
148             Object[] objArray = (Object[]) array.getClass().cast(array);
149             return objArray[index];
150         } else {
151             return getReferenceOrPrimitive(array, index);
152         }
153     }
154 
155     private static native Object getReferenceOrPrimitive(Object array, int index);
156 
157     /**
158      * Returns the value of the indexed component in the specified
159      * array object, as a {@code boolean}.
160      *
161      * @param array the array
162      * @param index the index
163      * @return the value of the indexed component in the specified array
164      * @throws    NullPointerException If the specified object is null
165      * @throws    IllegalArgumentException If the specified object is not
166      * an array, or if the indexed element cannot be converted to the
167      * return type by an identity or widening conversion
168      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
169      * argument is negative, or if it is greater than or equal to the
170      * length of the specified array
171      * @see Array#get
172      */
173     public static native boolean getBoolean(Object array, int index)
174         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
175 
176     /**
177      * Returns the value of the indexed component in the specified
178      * array object, as a {@code byte}.
179      *
180      * @param array the array
181      * @param index the index
182      * @return the value of the indexed component in the specified array
183      * @throws    NullPointerException If the specified object is null
184      * @throws    IllegalArgumentException If the specified object is not
185      * an array, or if the indexed element cannot be converted to the
186      * return type by an identity or widening conversion
187      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
188      * argument is negative, or if it is greater than or equal to the
189      * length of the specified array
190      * @see Array#get
191      */
192     public static native byte getByte(Object array, int index)
193         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
194 
195     /**
196      * Returns the value of the indexed component in the specified
197      * array object, as a {@code char}.
198      *
199      * @param array the array
200      * @param index the index
201      * @return the value of the indexed component in the specified array
202      * @throws    NullPointerException If the specified object is null
203      * @throws    IllegalArgumentException If the specified object is not
204      * an array, or if the indexed element cannot be converted to the
205      * return type by an identity or widening conversion
206      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
207      * argument is negative, or if it is greater than or equal to the
208      * length of the specified array
209      * @see Array#get
210      */
211     public static native char getChar(Object array, int index)
212         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
213 
214     /**
215      * Returns the value of the indexed component in the specified
216      * array object, as a {@code short}.
217      *
218      * @param array the array
219      * @param index the index
220      * @return the value of the indexed component in the specified array
221      * @throws    NullPointerException If the specified object is null
222      * @throws    IllegalArgumentException If the specified object is not
223      * an array, or if the indexed element cannot be converted to the
224      * return type by an identity or widening conversion
225      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
226      * argument is negative, or if it is greater than or equal to the
227      * length of the specified array
228      * @see Array#get
229      */
230     public static native short getShort(Object array, int index)
231         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
232 
233     /**
234      * Returns the value of the indexed component in the specified
235      * array object, as an {@code int}.
236      *
237      * @param array the array
238      * @param index the index
239      * @return the value of the indexed component in the specified array
240      * @throws    NullPointerException If the specified object is null
241      * @throws    IllegalArgumentException If the specified object is not
242      * an array, or if the indexed element cannot be converted to the
243      * return type by an identity or widening conversion
244      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
245      * argument is negative, or if it is greater than or equal to the
246      * length of the specified array
247      * @see Array#get
248      */
249     public static native int getInt(Object array, int index)
250         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
251 
252     /**
253      * Returns the value of the indexed component in the specified
254      * array object, as a {@code long}.
255      *
256      * @param array the array
257      * @param index the index
258      * @return the value of the indexed component in the specified array
259      * @throws    NullPointerException If the specified object is null
260      * @throws    IllegalArgumentException If the specified object is not
261      * an array, or if the indexed element cannot be converted to the
262      * return type by an identity or widening conversion
263      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
264      * argument is negative, or if it is greater than or equal to the
265      * length of the specified array
266      * @see Array#get
267      */
268     public static native long getLong(Object array, int index)
269         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
270 
271     /**
272      * Returns the value of the indexed component in the specified
273      * array object, as a {@code float}.
274      *
275      * @param array the array
276      * @param index the index
277      * @return the value of the indexed component in the specified array
278      * @throws    NullPointerException If the specified object is null
279      * @throws    IllegalArgumentException If the specified object is not
280      * an array, or if the indexed element cannot be converted to the
281      * return type by an identity or widening conversion
282      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
283      * argument is negative, or if it is greater than or equal to the
284      * length of the specified array
285      * @see Array#get
286      */
287     public static native float getFloat(Object array, int index)
288         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
289 
290     /**
291      * Returns the value of the indexed component in the specified
292      * array object, as a {@code double}.
293      *
294      * @param array the array
295      * @param index the index
296      * @return the value of the indexed component in the specified array
297      * @throws    NullPointerException If the specified object is null
298      * @throws    IllegalArgumentException If the specified object is not
299      * an array, or if the indexed element cannot be converted to the
300      * return type by an identity or widening conversion
301      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
302      * argument is negative, or if it is greater than or equal to the
303      * length of the specified array
304      * @see Array#get
305      */
306     public static native double getDouble(Object array, int index)
307         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
308 
309     /**
310      * Sets the value of the indexed component of the specified array
311      * object to the specified new value.  The new value is first
312      * automatically unwrapped if the array has a primitive component
313      * type.
314      * @param array the array
315      * @param index the index into the array
316      * @param value the new value of the indexed component
317      * @throws    NullPointerException If the specified object argument
318      * is null
319      * @throws    IllegalArgumentException If the specified object argument
320      * is not an array, or if the array component type is primitive and
321      * an unwrapping conversion fails
322      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
323      * argument is negative, or if it is greater than or equal to
324      * the length of the specified array
325      */
326     public static void set(Object array, int index, Object value)
327         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
328         Class<?> componentType = array.getClass().getComponentType();
329         if (componentType != null && !componentType.isPrimitive()) {
330             Object[] objArray = (Object[]) array.getClass().cast(array);
331             objArray[index] = componentType.cast(value);
332         } else {
333             setReferenceOrPrimitive(array, index, value);
334         }
335     }
336 
337     private static native void setReferenceOrPrimitive(Object array, int index, Object value);
338 
339     /**
340      * Sets the value of the indexed component of the specified array
341      * object to the specified {@code boolean} value.
342      * @param array the array
343      * @param index the index into the array
344      * @param z the new value of the indexed component
345      * @throws    NullPointerException If the specified object argument
346      * is null
347      * @throws    IllegalArgumentException If the specified object argument
348      * is not an array, or if the specified value cannot be converted
349      * to the underlying array's component type by an identity or a
350      * primitive widening conversion
351      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
352      * argument is negative, or if it is greater than or equal to
353      * the length of the specified array
354      * @see Array#set
355      */
356     public static native void setBoolean(Object array, int index, boolean z)
357         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
358 
359     /**
360      * Sets the value of the indexed component of the specified array
361      * object to the specified {@code byte} value.
362      * @param array the array
363      * @param index the index into the array
364      * @param b the new value of the indexed component
365      * @throws    NullPointerException If the specified object argument
366      * is null
367      * @throws    IllegalArgumentException If the specified object argument
368      * is not an array, or if the specified value cannot be converted
369      * to the underlying array's component type by an identity or a
370      * primitive widening conversion
371      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
372      * argument is negative, or if it is greater than or equal to
373      * the length of the specified array
374      * @see Array#set
375      */
376     public static native void setByte(Object array, int index, byte b)
377         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
378 
379     /**
380      * Sets the value of the indexed component of the specified array
381      * object to the specified {@code char} value.
382      * @param array the array
383      * @param index the index into the array
384      * @param c the new value of the indexed component
385      * @throws    NullPointerException If the specified object argument
386      * is null
387      * @throws    IllegalArgumentException If the specified object argument
388      * is not an array, or if the specified value cannot be converted
389      * to the underlying array's component type by an identity or a
390      * primitive widening conversion
391      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
392      * argument is negative, or if it is greater than or equal to
393      * the length of the specified array
394      * @see Array#set
395      */
396     public static native void setChar(Object array, int index, char c)
397         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
398 
399     /**
400      * Sets the value of the indexed component of the specified array
401      * object to the specified {@code short} value.
402      * @param array the array
403      * @param index the index into the array
404      * @param s the new value of the indexed component
405      * @throws    NullPointerException If the specified object argument
406      * is null
407      * @throws    IllegalArgumentException If the specified object argument
408      * is not an array, or if the specified value cannot be converted
409      * to the underlying array's component type by an identity or a
410      * primitive widening conversion
411      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
412      * argument is negative, or if it is greater than or equal to
413      * the length of the specified array
414      * @see Array#set
415      */
416     public static native void setShort(Object array, int index, short s)
417         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
418 
419     /**
420      * Sets the value of the indexed component of the specified array
421      * object to the specified {@code int} value.
422      * @param array the array
423      * @param index the index into the array
424      * @param i the new value of the indexed component
425      * @throws    NullPointerException If the specified object argument
426      * is null
427      * @throws    IllegalArgumentException If the specified object argument
428      * is not an array, or if the specified value cannot be converted
429      * to the underlying array's component type by an identity or a
430      * primitive widening conversion
431      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
432      * argument is negative, or if it is greater than or equal to
433      * the length of the specified array
434      * @see Array#set
435      */
436     public static native void setInt(Object array, int index, int i)
437         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
438 
439     /**
440      * Sets the value of the indexed component of the specified array
441      * object to the specified {@code long} value.
442      * @param array the array
443      * @param index the index into the array
444      * @param l the new value of the indexed component
445      * @throws    NullPointerException If the specified object argument
446      * is null
447      * @throws    IllegalArgumentException If the specified object argument
448      * is not an array, or if the specified value cannot be converted
449      * to the underlying array's component type by an identity or a
450      * primitive widening conversion
451      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
452      * argument is negative, or if it is greater than or equal to
453      * the length of the specified array
454      * @see Array#set
455      */
456     public static native void setLong(Object array, int index, long l)
457         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
458 
459     /**
460      * Sets the value of the indexed component of the specified array
461      * object to the specified {@code float} value.
462      * @param array the array
463      * @param index the index into the array
464      * @param f the new value of the indexed component
465      * @throws    NullPointerException If the specified object argument
466      * is null
467      * @throws    IllegalArgumentException If the specified object argument
468      * is not an array, or if the specified value cannot be converted
469      * to the underlying array's component type by an identity or a
470      * primitive widening conversion
471      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
472      * argument is negative, or if it is greater than or equal to
473      * the length of the specified array
474      * @see Array#set
475      */
476     public static native void setFloat(Object array, int index, float f)
477         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
478 
479     /**
480      * Sets the value of the indexed component of the specified array
481      * object to the specified {@code double} value.
482      * @param array the array
483      * @param index the index into the array
484      * @param d the new value of the indexed component
485      * @throws    NullPointerException If the specified object argument
486      * is null
487      * @throws    IllegalArgumentException If the specified object argument
488      * is not an array, or if the specified value cannot be converted
489      * to the underlying array's component type by an identity or a
490      * primitive widening conversion
491      * @throws    ArrayIndexOutOfBoundsException If the specified {@code index}
492      * argument is negative, or if it is greater than or equal to
493      * the length of the specified array
494      * @see Array#set
495      */
496     public static native void setDouble(Object array, int index, double d)
497         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
498 
499     /*
500      * Private
501      */
502 
503     @IntrinsicCandidate
504     private static native Object newArray(Class<?> componentType, int length)
505         throws NegativeArraySizeException;
506 
507     private static native Object multiNewArray(Class<?> componentType,
508         int[] dimensions)
509         throws IllegalArgumentException, NegativeArraySizeException;
510 
511 
512 }