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