2 * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
26 package java.lang.reflect;
28 import org.apidesign.bck2brwsr.core.Exported;
29 import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
32 * The {@code Array} class provides static methods to dynamically create and
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.
39 * @author Nakul Saraiya
41 @JavaScriptPrototype(prototype = "new Array", container = "Array.prototype")
46 * Constructor. Class Array is not instantiable.
51 * Creates a new array with the specified component type and
53 * Invoking this method is equivalent to creating an array
58 * Array.newInstance(componentType, x);
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 * @exception NullPointerException if the specified
67 * {@code componentType} parameter is null
68 * @exception IllegalArgumentException if componentType is {@link Void#TYPE}
69 * @exception NegativeArraySizeException if the specified {@code length}
72 public static Object newInstance(Class<?> componentType, int length)
73 throws NegativeArraySizeException {
75 throw new NegativeArraySizeException();
77 String sig = Method.findArraySignature(componentType);
78 return newArray(componentType.isPrimitive(), sig, null, length);
83 * with the specified component type and dimensions.
84 * If {@code componentType}
85 * represents a non-array class or interface, the new array
86 * has {@code dimensions.length} dimensions and
87 * {@code componentType} as its component type. If
88 * {@code componentType} represents an array class, the
89 * number of dimensions of the new array is equal to the sum
90 * of {@code dimensions.length} and the number of
91 * dimensions of {@code componentType}. In this case, the
92 * component type of the new array is the component type of
93 * {@code componentType}.
95 * <p>The number of dimensions of the new array must not
96 * exceed the number of array dimensions supported by the
97 * implementation (typically 255).
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
103 * @return the new array
104 * @exception NullPointerException if the specified
105 * {@code componentType} argument is null
106 * @exception IllegalArgumentException if the specified {@code dimensions}
107 * argument is a zero-dimensional array, or if the number of
108 * requested dimensions exceeds the limit on the number of array dimensions
109 * supported by the implementation (typically 255), or if componentType
110 * is {@link Void#TYPE}.
111 * @exception NegativeArraySizeException if any of the components in
112 * the specified {@code dimensions} argument is negative.
114 public static Object newInstance(Class<?> componentType, int... dimensions)
115 throws IllegalArgumentException, NegativeArraySizeException {
116 StringBuilder sig = new StringBuilder();
117 for (int i = 1; i < dimensions.length; i++) {
120 sig.append(Method.findArraySignature(componentType));
121 return multiNewArray(sig.toString(), dimensions, 0);
125 * Returns the length of the specified array object, as an {@code int}.
127 * @param array the array
128 * @return the length of the array
129 * @exception IllegalArgumentException if the object argument is not
132 public static int getLength(Object array)
133 throws IllegalArgumentException {
134 if (!array.getClass().isArray()) {
135 throw new IllegalArgumentException("Argument is not an array");
137 return Method.arrayLength(array);
141 * Returns the value of the indexed component in the specified
142 * array object. The value is automatically wrapped in an object
143 * if it has a primitive type.
145 * @param array the array
146 * @param index the index
147 * @return the (possibly wrapped) value of the indexed component in
148 * the specified array
149 * @exception NullPointerException If the specified object is null
150 * @exception IllegalArgumentException If the specified object is not
152 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
153 * argument is negative, or if it is greater than or equal to the
154 * length of the specified array
156 public static Object get(Object array, int index)
157 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
158 final Class<?> t = array.getClass().getComponentType();
159 if (t.isPrimitive()) {
160 return fromPrimitive(t, array, index);
162 return ((Object[])array)[index];
167 * Returns the value of the indexed component in the specified
168 * array object, as a {@code boolean}.
170 * @param array the array
171 * @param index the index
172 * @return the value of the indexed component in the specified array
173 * @exception NullPointerException If the specified object is null
174 * @exception IllegalArgumentException If the specified object is not
175 * an array, or if the indexed element cannot be converted to the
176 * return type by an identity or widening conversion
177 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
178 * argument is negative, or if it is greater than or equal to the
179 * length of the specified array
182 public static native boolean getBoolean(Object array, int index)
183 throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
186 * Returns the value of the indexed component in the specified
187 * array object, as a {@code byte}.
189 * @param array the array
190 * @param index the index
191 * @return the value of the indexed component in the specified array
192 * @exception NullPointerException If the specified object is null
193 * @exception IllegalArgumentException If the specified object is not
194 * an array, or if the indexed element cannot be converted to the
195 * return type by an identity or widening conversion
196 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
197 * argument is negative, or if it is greater than or equal to the
198 * length of the specified array
201 public static byte getByte(Object array, int index)
202 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
203 if (!Method.samePrimitive(array.getClass().getComponentType(), Byte.TYPE)) {
204 throw new IllegalArgumentException();
206 byte[] arr = (byte[]) array;
211 * Returns the value of the indexed component in the specified
212 * array object, as a {@code char}.
214 * @param array the array
215 * @param index the index
216 * @return the value of the indexed component in the specified array
217 * @exception NullPointerException If the specified object is null
218 * @exception IllegalArgumentException If the specified object is not
219 * an array, or if the indexed element cannot be converted to the
220 * return type by an identity or widening conversion
221 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
222 * argument is negative, or if it is greater than or equal to the
223 * length of the specified array
226 public static native char getChar(Object array, int index)
227 throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
230 * Returns the value of the indexed component in the specified
231 * array object, as a {@code short}.
233 * @param array the array
234 * @param index the index
235 * @return the value of the indexed component in the specified array
236 * @exception NullPointerException If the specified object is null
237 * @exception IllegalArgumentException If the specified object is not
238 * an array, or if the indexed element cannot be converted to the
239 * return type by an identity or widening conversion
240 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
241 * argument is negative, or if it is greater than or equal to the
242 * length of the specified array
245 public static short getShort(Object array, int index)
246 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
247 final Class<?> t = array.getClass().getComponentType();
248 if (Method.samePrimitive(t, Short.TYPE)) {
249 short[] arr = (short[]) array;
252 return getByte(array, index);
256 * Returns the value of the indexed component in the specified
257 * array object, as an {@code int}.
259 * @param array the array
260 * @param index the index
261 * @return the value of the indexed component in the specified array
262 * @exception NullPointerException If the specified object is null
263 * @exception IllegalArgumentException If the specified object is not
264 * an array, or if the indexed element cannot be converted to the
265 * return type by an identity or widening conversion
266 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
267 * argument is negative, or if it is greater than or equal to the
268 * length of the specified array
271 public static int getInt(Object array, int index)
272 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
273 final Class<?> t = array.getClass().getComponentType();
274 if (Method.samePrimitive(t, Integer.TYPE)) {
275 int[] arr = (int[]) array;
278 return getShort(array, index);
282 * Returns the value of the indexed component in the specified
283 * array object, as a {@code long}.
285 * @param array the array
286 * @param index the index
287 * @return the value of the indexed component in the specified array
288 * @exception NullPointerException If the specified object is null
289 * @exception IllegalArgumentException If the specified object is not
290 * an array, or if the indexed element cannot be converted to the
291 * return type by an identity or widening conversion
292 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
293 * argument is negative, or if it is greater than or equal to the
294 * length of the specified array
297 public static long getLong(Object array, int index)
298 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
299 final Class<?> t = array.getClass().getComponentType();
300 if (Method.samePrimitive(t, Long.TYPE)) {
301 long[] arr = (long[]) array;
304 return getInt(array, index);
308 * Returns the value of the indexed component in the specified
309 * array object, as a {@code float}.
311 * @param array the array
312 * @param index the index
313 * @return the value of the indexed component in the specified array
314 * @exception NullPointerException If the specified object is null
315 * @exception IllegalArgumentException If the specified object is not
316 * an array, or if the indexed element cannot be converted to the
317 * return type by an identity or widening conversion
318 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
319 * argument is negative, or if it is greater than or equal to the
320 * length of the specified array
323 public static float getFloat(Object array, int index)
324 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
325 final Class<?> t = array.getClass().getComponentType();
326 if (Method.samePrimitive(t, Float.TYPE)) {
327 float[] arr = (float[]) array;
330 return getLong(array, index);
334 * Returns the value of the indexed component in the specified
335 * array object, as a {@code double}.
337 * @param array the array
338 * @param index the index
339 * @return the value of the indexed component in the specified array
340 * @exception NullPointerException If the specified object is null
341 * @exception IllegalArgumentException If the specified object is not
342 * an array, or if the indexed element cannot be converted to the
343 * return type by an identity or widening conversion
344 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
345 * argument is negative, or if it is greater than or equal to the
346 * length of the specified array
349 public static double getDouble(Object array, int index)
350 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
351 final Class<?> t = array.getClass().getComponentType();
352 if (Method.samePrimitive(t, Double.TYPE)) {
353 double[] arr = (double[]) array;
356 return getFloat(array, index);
360 * Sets the value of the indexed component of the specified array
361 * object to the specified new value. The new value is first
362 * automatically unwrapped if the array has a primitive component
364 * @param array the array
365 * @param index the index into the array
366 * @param value the new value of the indexed component
367 * @exception NullPointerException If the specified object argument
369 * @exception IllegalArgumentException If the specified object argument
370 * is not an array, or if the array component type is primitive and
371 * an unwrapping conversion fails
372 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
373 * argument is negative, or if it is greater than or equal to
374 * the length of the specified array
376 public static void set(Object array, int index, Object value)
377 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
378 if (array.getClass().getComponentType().isPrimitive()) {
379 throw new IllegalArgumentException();
381 Object[] arr = (Object[])array;
387 * Sets the value of the indexed component of the specified array
388 * object to the specified {@code boolean} value.
389 * @param array the array
390 * @param index the index into the array
391 * @param z the new value of the indexed component
392 * @exception NullPointerException If the specified object argument
394 * @exception IllegalArgumentException If the specified object argument
395 * is not an array, or if the specified value cannot be converted
396 * to the underlying array's component type by an identity or a
397 * primitive widening conversion
398 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
399 * argument is negative, or if it is greater than or equal to
400 * the length of the specified array
403 public static native void setBoolean(Object array, int index, boolean z)
404 throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
407 * Sets the value of the indexed component of the specified array
408 * object to the specified {@code byte} value.
409 * @param array the array
410 * @param index the index into the array
411 * @param b the new value of the indexed component
412 * @exception NullPointerException If the specified object argument
414 * @exception IllegalArgumentException If the specified object argument
415 * is not an array, or if the specified value cannot be converted
416 * to the underlying array's component type by an identity or a
417 * primitive widening conversion
418 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
419 * argument is negative, or if it is greater than or equal to
420 * the length of the specified array
423 public static void setByte(Object array, int index, byte b)
424 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
425 Class<?> t = array.getClass().getComponentType();
426 if (Method.samePrimitive(t, Byte.TYPE)) {
427 byte[] arr = (byte[]) array;
430 setShort(array, index, b);
435 * Sets the value of the indexed component of the specified array
436 * object to the specified {@code char} value.
437 * @param array the array
438 * @param index the index into the array
439 * @param c the new value of the indexed component
440 * @exception NullPointerException If the specified object argument
442 * @exception IllegalArgumentException If the specified object argument
443 * is not an array, or if the specified value cannot be converted
444 * to the underlying array's component type by an identity or a
445 * primitive widening conversion
446 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
447 * argument is negative, or if it is greater than or equal to
448 * the length of the specified array
451 public static native void setChar(Object array, int index, char c)
452 throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
455 * Sets the value of the indexed component of the specified array
456 * object to the specified {@code short} value.
457 * @param array the array
458 * @param index the index into the array
459 * @param s the new value of the indexed component
460 * @exception NullPointerException If the specified object argument
462 * @exception IllegalArgumentException If the specified object argument
463 * is not an array, or if the specified value cannot be converted
464 * to the underlying array's component type by an identity or a
465 * primitive widening conversion
466 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
467 * argument is negative, or if it is greater than or equal to
468 * the length of the specified array
471 public static void setShort(Object array, int index, short s)
472 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
473 Class<?> t = array.getClass().getComponentType();
474 if (Method.samePrimitive(t, Short.TYPE)) {
475 short[] arr = (short[]) array;
478 setInt(array, index, s);
484 * Sets the value of the indexed component of the specified array
485 * object to the specified {@code int} value.
486 * @param array the array
487 * @param index the index into the array
488 * @param i the new value of the indexed component
489 * @exception NullPointerException If the specified object argument
491 * @exception IllegalArgumentException If the specified object argument
492 * is not an array, or if the specified value cannot be converted
493 * to the underlying array's component type by an identity or a
494 * primitive widening conversion
495 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
496 * argument is negative, or if it is greater than or equal to
497 * the length of the specified array
500 public static void setInt(Object array, int index, int i)
501 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
502 Class<?> t = array.getClass().getComponentType();
503 if (Method.samePrimitive(t, Integer.TYPE)) {
504 int[] arr = (int[]) array;
507 setLong(array, index, i);
512 * Sets the value of the indexed component of the specified array
513 * object to the specified {@code long} value.
514 * @param array the array
515 * @param index the index into the array
516 * @param l the new value of the indexed component
517 * @exception NullPointerException If the specified object argument
519 * @exception IllegalArgumentException If the specified object argument
520 * is not an array, or if the specified value cannot be converted
521 * to the underlying array's component type by an identity or a
522 * primitive widening conversion
523 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
524 * argument is negative, or if it is greater than or equal to
525 * the length of the specified array
528 public static void setLong(Object array, int index, long l)
529 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
530 Class<?> t = array.getClass().getComponentType();
531 if (Method.samePrimitive(t, Long.TYPE)) {
532 long[] arr = (long[]) array;
535 setFloat(array, index, l);
540 * Sets the value of the indexed component of the specified array
541 * object to the specified {@code float} value.
542 * @param array the array
543 * @param index the index into the array
544 * @param f the new value of the indexed component
545 * @exception NullPointerException If the specified object argument
547 * @exception IllegalArgumentException If the specified object argument
548 * is not an array, or if the specified value cannot be converted
549 * to the underlying array's component type by an identity or a
550 * primitive widening conversion
551 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
552 * argument is negative, or if it is greater than or equal to
553 * the length of the specified array
556 public static void setFloat(Object array, int index, float f)
557 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
558 Class<?> t = array.getClass().getComponentType();
559 if (Method.samePrimitive(t, Float.TYPE)) {
560 float[] arr = (float[])array;
563 setDouble(array, index, f);
568 * Sets the value of the indexed component of the specified array
569 * object to the specified {@code double} value.
570 * @param array the array
571 * @param index the index into the array
572 * @param d the new value of the indexed component
573 * @exception NullPointerException If the specified object argument
575 * @exception IllegalArgumentException If the specified object argument
576 * is not an array, or if the specified value cannot be converted
577 * to the underlying array's component type by an identity or a
578 * primitive widening conversion
579 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
580 * argument is negative, or if it is greater than or equal to
581 * the length of the specified array
584 public static void setDouble(Object array, int index, double d)
585 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
586 Class<?> t = array.getClass().getComponentType();
587 if (Method.samePrimitive(t, Double.TYPE)) {
588 double[] arr = (double[])array;
591 throw new IllegalArgumentException("argument type mismatch");
600 private static Object newArray(boolean primitive, String sig, Object fn, int length) {
601 return Method.newArray(primitive, sig, fn, length);
605 private static boolean isInstance(Object arr, String sig) {
609 return sig.equals(arr.getClass().getName());
613 private static boolean isInstance(Object arr, int dimensions, Object fn) throws ClassNotFoundException {
617 // log("isInstance for " + arr + " and " + dimensions);
618 Class<?> c = arr.getClass();
619 while (dimensions-- > 0) {
620 // log(" class: " + c);
621 c = c.getComponentType();
622 // log(" next class: " + c);
627 Class<?> t = Method.classFromFn(fn);
628 // log(" to check: " + t);
629 return t.isAssignableFrom(c);
632 // @JavaScriptBody(args = { "m" }, body = "java.lang.System.out.println(m.toString().toString());")
633 // private static native void log(Object m);
636 private static Object multiNewArray(String sig, int[] dims, Object fn)
637 throws IllegalArgumentException, NegativeArraySizeException {
638 return multiNewArray(sig, dims, 0, fn);
640 private static Object multiNewArray(String sig, int[] dims, int index, Object fn)
641 throws IllegalArgumentException, NegativeArraySizeException {
642 if (dims.length == index + 1) {
643 return newArray(sig.length() == 2, sig, fn, dims[index]);
645 Object arr = newArray(false, sig, null, dims[index]);
646 String compsig = sig.substring(1);
647 int len = getLength(arr);
648 for (int i = 0; i < len; i++) {
649 Method.setArray(arr, i, multiNewArray(compsig, dims, index + 1, fn));
653 private static Object fromPrimitive(Class<?> t, Object array, int index) {
654 return Method.fromPrimitive(t, Method.atArray(array, index));