1 /* java.lang.reflect.Array - manipulate arrays by reflection 2 Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package java.lang.reflect; 40 41 /** 42 * Array holds static helper functions that allow you to create and 43 * manipulate arrays by reflection. Operations know how to perform widening 44 * conversions, but throw {@link IllegalArgumentException} if you attempt 45 * a narrowing conversion. Also, when accessing primitive arrays, this 46 * class performs object wrapping and unwrapping as necessary.<p> 47 * 48 * <B>Note:</B> This class returns and accepts types as Classes, even 49 * primitive types; there are Class types defined that represent each 50 * different primitive type. They are <code>java.lang.Boolean.TYPE, 51 * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class, 52 * byte.class</code>, etc. These are not to be confused with the 53 * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are 54 * real classes. Note also that the shorthand <code>Object[].class</code> 55 * is a convenient way to get array Classes.<p> 56 * 57 * <B>Performance note:</B> This class performs best when it does not have 58 * to convert primitive types. The further along the chain it has to convert, 59 * the worse performance will be. You're best off using the array as whatever 60 * type it already is, and then converting the result. You will do even 61 * worse if you do this and use the generic set() function. 62 * 63 * @author John Keiser 64 * @author Eric Blake (ebb9@email.byu.edu) 65 * @author Per Bothner (bothner@cygnus.com) 66 * @see java.lang.Boolean#TYPE 67 * @see java.lang.Byte#TYPE 68 * @see java.lang.Short#TYPE 69 * @see java.lang.Character#TYPE 70 * @see java.lang.Integer#TYPE 71 * @see java.lang.Long#TYPE 72 * @see java.lang.Float#TYPE 73 * @see java.lang.Double#TYPE 74 * @since 1.1 75 * @status updated to 1.4 76 */ 77 public final class Array 78 { 79 80 /** 81 * This class is uninstantiable. 82 */ Array()83 private Array() 84 { 85 } 86 87 /** 88 * Creates a new single-dimensioned array. 89 * @param componentType the type of the array to create 90 * @param length the length of the array to create 91 * @return the created array, cast to an Object 92 * @throws NullPointerException if <code>componentType</code> is null 93 * @throws IllegalArgumentException if <code>componentType</code> is 94 * <code>Void.TYPE</code> 95 * @throws NegativeArraySizeException when length is less than 0 96 * @throws OutOfMemoryError if memory allocation fails 97 */ newInstance(Class<?> componentType, int length)98 public static Object newInstance(Class<?> componentType, int length) 99 { 100 if (! componentType.isPrimitive()) 101 return VMArray.createObjectArray(componentType, length); 102 if (componentType == boolean.class) 103 return new boolean[length]; 104 if (componentType == byte.class) 105 return new byte[length]; 106 if (componentType == char.class) 107 return new char[length]; 108 if (componentType == short.class) 109 return new short[length]; 110 if (componentType == int.class) 111 return new int[length]; 112 if (componentType == long.class) 113 return new long[length]; 114 if (componentType == float.class) 115 return new float[length]; 116 if (componentType == double.class) 117 return new double[length]; 118 // assert componentType == void.class 119 throw new IllegalArgumentException(); 120 } 121 122 /** 123 * Creates a new multi-dimensioned array. The new array has the same 124 * component type as the argument class, and the number of dimensions 125 * in the new array is the sum of the dimensions of the argument class 126 * and the length of the argument dimensions. Virtual Machine limitations 127 * forbid too many dimensions (usually 255 is the maximum); but even 128 * 50 dimensions of 2 elements in each dimension would exceed your memory 129 * long beforehand! 130 * 131 * @param componentType the type of the array to create. 132 * @param dimensions the dimensions of the array to create. Each element 133 * in <code>dimensions</code> makes another dimension of the new 134 * array. Thus, <code>Array.newInstance(java.lang.Boolean, 135 * new int[]{1,2,3})</code> is the same as 136 * <code>new java.lang.Boolean[1][2][3]</code> 137 * @return the created array, cast to an Object 138 * @throws NullPointerException if componentType or dimension is null 139 * @throws IllegalArgumentException if the the size of 140 * <code>dimensions</code> is 0 or exceeds the maximum number of 141 * array dimensions in the VM; or if componentType is Void.TYPE 142 * @throws NegativeArraySizeException when any of the dimensions is less 143 * than 0 144 * @throws OutOfMemoryError if memory allocation fails 145 */ newInstance(Class<?> componentType, int[] dimensions)146 public static Object newInstance(Class<?> componentType, int[] dimensions) 147 { 148 if (dimensions.length <= 0) 149 throw new IllegalArgumentException ("Empty dimensions array."); 150 return createMultiArray(componentType, dimensions, 0); 151 } 152 153 /** 154 * Gets the array length. 155 * @param array the array 156 * @return the length of the array 157 * @throws IllegalArgumentException if <code>array</code> is not an array 158 * @throws NullPointerException if <code>array</code> is null 159 */ getLength(Object array)160 public static int getLength(Object array) 161 { 162 if (array instanceof Object[]) 163 return ((Object[]) array).length; 164 if (array instanceof boolean[]) 165 return ((boolean[]) array).length; 166 if (array instanceof byte[]) 167 return ((byte[]) array). length; 168 if (array instanceof char[]) 169 return ((char[]) array).length; 170 if (array instanceof short[]) 171 return ((short[]) array).length; 172 if (array instanceof int[]) 173 return ((int[]) array).length; 174 if (array instanceof long[]) 175 return ((long[]) array).length; 176 if (array instanceof float[]) 177 return ((float[]) array).length; 178 if (array instanceof double[]) 179 return ((double[]) array).length; 180 if (array == null) 181 throw new NullPointerException(); 182 throw new IllegalArgumentException(); 183 } 184 185 /** 186 * Gets an element of an array. Primitive elements will be wrapped in 187 * the corresponding class type. 188 * 189 * @param array the array to access 190 * @param index the array index to access 191 * @return the element at <code>array[index]</code> 192 * @throws IllegalArgumentException if <code>array</code> is not an array 193 * @throws NullPointerException if <code>array</code> is null 194 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 195 * bounds 196 * @see #getBoolean(Object, int) 197 * @see #getByte(Object, int) 198 * @see #getChar(Object, int) 199 * @see #getShort(Object, int) 200 * @see #getInt(Object, int) 201 * @see #getLong(Object, int) 202 * @see #getFloat(Object, int) 203 * @see #getDouble(Object, int) 204 */ get(Object array, int index)205 public static Object get(Object array, int index) 206 { 207 if (array instanceof Object[]) 208 return ((Object[]) array)[index]; 209 if (array instanceof boolean[]) 210 return ((boolean[]) array)[index] ? Boolean.TRUE : Boolean.FALSE; 211 if (array instanceof byte[]) 212 return Byte.valueOf(((byte[]) array)[index]); 213 if (array instanceof char[]) 214 return Character.valueOf(((char[]) array)[index]); 215 if (array instanceof short[]) 216 return Short.valueOf(((short[]) array)[index]); 217 if (array instanceof int[]) 218 return Integer.valueOf(((int[]) array)[index]); 219 if (array instanceof long[]) 220 return Long.valueOf(((long[]) array)[index]); 221 if (array instanceof float[]) 222 return Float.valueOf(((float[]) array)[index]); 223 if (array instanceof double[]) 224 return Double.valueOf(((double[]) array)[index]); 225 if (array == null) 226 throw new NullPointerException(); 227 throw new IllegalArgumentException(); 228 } 229 230 /** 231 * Gets an element of a boolean array. 232 * 233 * @param array the array to access 234 * @param index the array index to access 235 * @return the boolean element at <code>array[index]</code> 236 * @throws IllegalArgumentException if <code>array</code> is not a boolean 237 * array 238 * @throws NullPointerException if <code>array</code> is null 239 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 240 * bounds 241 * @see #get(Object, int) 242 */ getBoolean(Object array, int index)243 public static boolean getBoolean(Object array, int index) 244 { 245 if (array instanceof boolean[]) 246 return ((boolean[]) array)[index]; 247 if (array == null) 248 throw new NullPointerException(); 249 throw new IllegalArgumentException(); 250 } 251 252 /** 253 * Gets an element of a byte array. 254 * 255 * @param array the array to access 256 * @param index the array index to access 257 * @return the byte element at <code>array[index]</code> 258 * @throws IllegalArgumentException if <code>array</code> is not a byte 259 * array 260 * @throws NullPointerException if <code>array</code> is null 261 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 262 * bounds 263 * @see #get(Object, int) 264 */ getByte(Object array, int index)265 public static byte getByte(Object array, int index) 266 { 267 if (array instanceof byte[]) 268 return ((byte[]) array)[index]; 269 if (array == null) 270 throw new NullPointerException(); 271 throw new IllegalArgumentException(); 272 } 273 274 /** 275 * Gets an element of a char array. 276 * 277 * @param array the array to access 278 * @param index the array index to access 279 * @return the char element at <code>array[index]</code> 280 * @throws IllegalArgumentException if <code>array</code> is not a char 281 * array 282 * @throws NullPointerException if <code>array</code> is null 283 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 284 * bounds 285 * @see #get(Object, int) 286 */ getChar(Object array, int index)287 public static char getChar(Object array, int index) 288 { 289 if (array instanceof char[]) 290 return ((char[]) array)[index]; 291 if (array == null) 292 throw new NullPointerException(); 293 throw new IllegalArgumentException(); 294 } 295 296 /** 297 * Gets an element of a short array. 298 * 299 * @param array the array to access 300 * @param index the array index to access 301 * @return the short element at <code>array[index]</code> 302 * @throws IllegalArgumentException if <code>array</code> is not a byte 303 * or char array 304 * @throws NullPointerException if <code>array</code> is null 305 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 306 * bounds 307 * @see #get(Object, int) 308 */ getShort(Object array, int index)309 public static short getShort(Object array, int index) 310 { 311 if (array instanceof short[]) 312 return ((short[]) array)[index]; 313 return getByte(array, index); 314 } 315 316 /** 317 * Gets an element of an int array. 318 * 319 * @param array the array to access 320 * @param index the array index to access 321 * @return the int element at <code>array[index]</code> 322 * @throws IllegalArgumentException if <code>array</code> is not a byte, 323 * char, short, or int array 324 * @throws NullPointerException if <code>array</code> is null 325 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 326 * bounds 327 * @see #get(Object, int) 328 */ getInt(Object array, int index)329 public static int getInt(Object array, int index) 330 { 331 if (array instanceof int[]) 332 return ((int[]) array)[index]; 333 if (array instanceof char[]) 334 return ((char[]) array)[index]; 335 return getShort(array, index); 336 } 337 338 /** 339 * Gets an element of a long array. 340 * 341 * @param array the array to access 342 * @param index the array index to access 343 * @return the long element at <code>array[index]</code> 344 * @throws IllegalArgumentException if <code>array</code> is not a byte, 345 * char, short, int, or long array 346 * @throws NullPointerException if <code>array</code> is null 347 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 348 * bounds 349 * @see #get(Object, int) 350 */ getLong(Object array, int index)351 public static long getLong(Object array, int index) 352 { 353 if (array instanceof long[]) 354 return ((long[]) array)[index]; 355 return getInt(array, index); 356 } 357 358 /** 359 * Gets an element of a float array. 360 * 361 * @param array the array to access 362 * @param index the array index to access 363 * @return the float element at <code>array[index]</code> 364 * @throws IllegalArgumentException if <code>array</code> is not a byte, 365 * char, short, int, long, or float array 366 * @throws NullPointerException if <code>array</code> is null 367 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 368 * bounds 369 * @see #get(Object, int) 370 */ getFloat(Object array, int index)371 public static float getFloat(Object array, int index) 372 { 373 if (array instanceof float[]) 374 return ((float[]) array)[index]; 375 return getLong(array, index); 376 } 377 378 /** 379 * Gets an element of a double array. 380 * 381 * @param array the array to access 382 * @param index the array index to access 383 * @return the double element at <code>array[index]</code> 384 * @throws IllegalArgumentException if <code>array</code> is not a byte, 385 * char, short, int, long, float, or double array 386 * @throws NullPointerException if <code>array</code> is null 387 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 388 * bounds 389 * @see #get(Object, int) 390 */ getDouble(Object array, int index)391 public static double getDouble(Object array, int index) 392 { 393 if (array instanceof double[]) 394 return ((double[]) array)[index]; 395 return getFloat(array, index); 396 } 397 398 /** 399 * Sets an element of an array. If the array is primitive, then the new 400 * value is unwrapped and widened. 401 * 402 * @param array the array to set a value of 403 * @param index the array index to set the value to 404 * @param value the value to set 405 * @throws IllegalArgumentException if <code>array</code> is not an array, 406 * or the array is primitive and unwrapping value fails, or the 407 * value is not assignable to the array component type 408 * @throws NullPointerException if array is null, or if array is primitive 409 * and value is null 410 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 411 * bounds 412 * @see #setBoolean(Object, int, boolean) 413 * @see #setByte(Object, int, byte) 414 * @see #setChar(Object, int, char) 415 * @see #setShort(Object, int, short) 416 * @see #setInt(Object, int, int) 417 * @see #setLong(Object, int, long) 418 * @see #setFloat(Object, int, float) 419 * @see #setDouble(Object, int, double) 420 */ set(Object array, int index, Object value)421 public static void set(Object array, int index, Object value) 422 { 423 if (array instanceof Object[]) 424 { 425 // Too bad the API won't let us throw the easier ArrayStoreException! 426 if (value != null 427 && ! array.getClass().getComponentType().isInstance(value)) 428 throw new IllegalArgumentException(); 429 ((Object[]) array)[index] = value; 430 } 431 else if (value instanceof Byte) 432 setByte(array, index, ((Byte) value).byteValue()); 433 else if (value instanceof Short) 434 setShort(array, index, ((Short) value).shortValue()); 435 else if (value instanceof Integer) 436 setInt(array, index, ((Integer) value).intValue()); 437 else if (value instanceof Long) 438 setLong(array, index, ((Long) value).longValue()); 439 else if (value instanceof Float) 440 setFloat(array, index, ((Float) value).floatValue()); 441 else if (value instanceof Double) 442 setDouble(array, index, ((Double) value).doubleValue()); 443 else if (value instanceof Character) 444 setChar(array, index, ((Character) value).charValue()); 445 else if (value instanceof Boolean) 446 setBoolean(array, index, ((Boolean) value).booleanValue()); 447 else if (array == null) 448 throw new NullPointerException(); 449 else 450 throw new IllegalArgumentException(); 451 } 452 453 /** 454 * Sets an element of a boolean array. 455 * 456 * @param array the array to set a value of 457 * @param index the array index to set the value to 458 * @param value the value to set 459 * @throws IllegalArgumentException if <code>array</code> is not a boolean 460 * array 461 * @throws NullPointerException if <code>array</code> is null 462 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 463 * bounds 464 * @see #set(Object, int, Object) 465 */ setBoolean(Object array, int index, boolean value)466 public static void setBoolean(Object array, int index, boolean value) 467 { 468 if (array instanceof boolean[]) 469 ((boolean[]) array)[index] = value; 470 else if (array == null) 471 throw new NullPointerException(); 472 else 473 throw new IllegalArgumentException(); 474 } 475 476 /** 477 * Sets an element of a byte array. 478 * 479 * @param array the array to set a value of 480 * @param index the array index to set the value to 481 * @param value the value to set 482 * @throws IllegalArgumentException if <code>array</code> is not a byte, 483 * short, int, long, float, or double array 484 * @throws NullPointerException if <code>array</code> is null 485 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 486 * bounds 487 * @see #set(Object, int, Object) 488 */ setByte(Object array, int index, byte value)489 public static void setByte(Object array, int index, byte value) 490 { 491 if (array instanceof byte[]) 492 ((byte[]) array)[index] = value; 493 else 494 setShort(array, index, value); 495 } 496 497 /** 498 * Sets an element of a char array. 499 * 500 * @param array the array to set a value of 501 * @param index the array index to set the value to 502 * @param value the value to set 503 * @throws IllegalArgumentException if <code>array</code> is not a char, 504 * int, long, float, or double array 505 * @throws NullPointerException if <code>array</code> is null 506 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 507 * bounds 508 * @see #set(Object, int, Object) 509 */ setChar(Object array, int index, char value)510 public static void setChar(Object array, int index, char value) 511 { 512 if (array instanceof char[]) 513 ((char[]) array)[index] = value; 514 else 515 setInt(array, index, value); 516 } 517 518 /** 519 * Sets an element of a short array. 520 * 521 * @param array the array to set a value of 522 * @param index the array index to set the value to 523 * @param value the value to set 524 * @throws IllegalArgumentException if <code>array</code> is not a short, 525 * int, long, float, or double array 526 * @throws NullPointerException if <code>array</code> is null 527 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 528 * bounds 529 * @see #set(Object, int, Object) 530 */ setShort(Object array, int index, short value)531 public static void setShort(Object array, int index, short value) 532 { 533 if (array instanceof short[]) 534 ((short[]) array)[index] = value; 535 else 536 setInt(array, index, value); 537 } 538 539 /** 540 * Sets an element of an int array. 541 * 542 * @param array the array to set a value of 543 * @param index the array index to set the value to 544 * @param value the value to set 545 * @throws IllegalArgumentException if <code>array</code> is not an int, 546 * long, float, or double array 547 * @throws NullPointerException if <code>array</code> is null 548 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 549 * bounds 550 * @see #set(Object, int, Object) 551 */ setInt(Object array, int index, int value)552 public static void setInt(Object array, int index, int value) 553 { 554 if (array instanceof int[]) 555 ((int[]) array)[index] = value; 556 else 557 setLong(array, index, value); 558 } 559 560 /** 561 * Sets an element of a long array. 562 * 563 * @param array the array to set a value of 564 * @param index the array index to set the value to 565 * @param value the value to set 566 * @throws IllegalArgumentException if <code>array</code> is not a long, 567 * float, or double array 568 * @throws NullPointerException if <code>array</code> is null 569 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 570 * bounds 571 * @see #set(Object, int, Object) 572 */ setLong(Object array, int index, long value)573 public static void setLong(Object array, int index, long value) 574 { 575 if (array instanceof long[]) 576 ((long[]) array)[index] = value; 577 else 578 setFloat(array, index, value); 579 } 580 581 /** 582 * Sets an element of a float array. 583 * 584 * @param array the array to set a value of 585 * @param index the array index to set the value to 586 * @param value the value to set 587 * @throws IllegalArgumentException if <code>array</code> is not a float 588 * or double array 589 * @throws NullPointerException if <code>array</code> is null 590 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 591 * bounds 592 * @see #set(Object, int, Object) 593 */ setFloat(Object array, int index, float value)594 public static void setFloat(Object array, int index, float value) 595 { 596 if (array instanceof float[]) 597 ((float[]) array)[index] = value; 598 else 599 setDouble(array, index, value); 600 } 601 602 /** 603 * Sets an element of a double array. 604 * 605 * @param array the array to set a value of 606 * @param index the array index to set the value to 607 * @param value the value to set 608 * @throws IllegalArgumentException if <code>array</code> is not a double 609 * array 610 * @throws NullPointerException if <code>array</code> is null 611 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of 612 * bounds 613 * @see #set(Object, int, Object) 614 */ setDouble(Object array, int index, double value)615 public static void setDouble(Object array, int index, double value) 616 { 617 if (array instanceof double[]) 618 ((double[]) array)[index] = value; 619 else if (array == null) 620 throw new NullPointerException(); 621 else 622 throw new IllegalArgumentException(); 623 } 624 625 /** 626 * Dynamically and recursively create a multi-dimensioned array of objects. 627 * 628 * @param type guaranteed to be a valid object type 629 * @param dimensions the dimensions of the array 630 * @param index index of the current dimension to build 631 * @return the new multi-dimensioned array 632 * @throws NegativeArraySizeException if any entry of dimensions is negative 633 * @throws OutOfMemoryError if memory allocation fails 634 */ 635 // This would be faster if implemented natively, using the multianewarray 636 // bytecode instead of this recursive call createMultiArray(Class type, int[] dimensions, int index)637 private static Object createMultiArray(Class type, int[] dimensions, 638 int index) 639 { 640 if (index == dimensions.length - 1) 641 return newInstance(type, dimensions[index]); 642 643 Object toAdd = createMultiArray(type, dimensions, index + 1); 644 Class thisType = toAdd.getClass(); 645 Object[] retval 646 = (Object[]) VMArray.createObjectArray(thisType, dimensions[index]); 647 if (dimensions[index] > 0) 648 retval[0] = toAdd; 649 int i = dimensions[index]; 650 while (--i > 0) 651 retval[i] = createMultiArray(type, dimensions, index + 1); 652 return retval; 653 } 654 655 } 656