View Javadoc
1   
2   package eu.simuline.util;
3   
4   import java.lang.reflect.Array;
5   
6   import java.util.List;
7   import java.util.ArrayList;
8   import java.util.Comparator;
9   import java.util.Arrays;
10  
11  /**
12   * An add on to the class {@link java.util.Arrays}. 
13   * Partially this is influenced by {@link java.util.Collections}. 
14   *
15   * @param <E>
16   *    The type of the entry of the array under consideration. 
17   *
18   * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
19   * @version 1.0
20   */
21  public final class ArraysExt<E> {
22  
23      /* -------------------------------------------------------------------- *
24       * class constants.                                                     *
25       * -------------------------------------------------------------------- */
26  
27      /**
28       * The class <code>double[]</code>. 
29       */
30      //public static final Class<?> DOUBLE_ARRAY1 = getArrayCls(Double.TYPE,1);
31  
32      /**
33       * The class <code>double[][]</code>. 
34       */
35      //public static final Class<?> DOUBLE_ARRAY2 = getArrayCls(Double.TYPE,2);
36  
37      public static final Object[] EMPTY = new Object[] {};
38  
39      /* -------------------------------------------------------------------- *
40       * constructors.                                                        *
41       * -------------------------------------------------------------------- */
42  
43      private ArraysExt() {
44      }
45  
46      /* -------------------------------------------------------------------- *
47       * static methods.                                                      *
48       * -------------------------------------------------------------------- */
49  
50      /**
51       * Reverses the order of the elements in the specified array. 
52       * This method runs in linear time.
53       *
54       * @param array 
55       *    the array whose elements are to be reversed. 
56       */
57      public static void reverse(Object[] array) {
58  	Object tmp;
59  	for (int i = 0; i < array.length / 2; i++) {
60  	    tmp = array[i];
61  	    array[i] = array[array.length - 1 - i];
62  	    array[array.length - 1 - i] = tmp;
63  	}
64      }
65  
66      /**
67       * Replaces all of the elements of the specified array 
68       * with the specified element. 
69       * This method runs in linear time.
70       *
71       * @param array 
72       *    the array to be filled with the specified element. 
73       * @param  obj 
74       *    The element with which to fill the specified array. 
75       */
76      public static void fill(Object[] array, Object obj) {
77  	for (int i = 0; i < array.length; i++) {
78  	    array[i] = obj;
79  	}
80      }
81  
82      /**
83       * Returns an array consisting of <tt>n</tt> copies 
84       * of the specified object. 
85       * The newly allocated data object is tiny 
86       * (it contains a single reference to the data object). 
87       *
88       * @param  num 
89       *    the number of elements in the returned list.
90       * @param  obj 
91       *    the element to appear repeatedly in the returned list.
92       * @return 
93       *    an array consisting of <tt>n</tt> copies 
94       * 	  of the specified object. 
95       * @throws IllegalArgumentException 
96       *    if n &lt; 0. 
97       */
98      public static Object[] nCopies(int num, Object obj) {
99  	if (num < 0) {
100 	     throw new IllegalArgumentException
101 		 ("Requested negative number of copies: " + num + ". ");
102 	}
103 	
104 	Object[] result = new Object[num];
105 	fill(result, obj);
106 	return result;
107     }
108 
109     /**
110      * Turns the given array recursively 
111      * into a hierarchy of nested lists. 
112      * Note that unlike Arrays.asList, this is not a simple wrapper! 
113      *
114      * @param array 
115      *    an array of objects which may in turn be arrays of objects. 
116      * @return 
117      *    a list <code>list</code> of objects satisfying 
118      *    <code>list.get(i) == array[i]</code> 
119      *    if <code>array[i]</code> is not an <code>Object[]</code>; 
120      *    <code>list.get(i) == recAsList(array[i])</code> otherwise. 
121      *    Note that <code>list</code> may be a nested list. 
122      * @see CollectionsExt#recToArray(List)
123      */
124     public static List<Object> recAsList(Object[] array) {
125 	List<Object> result = new ArrayList<Object>();
126 	for (Object obj : array) {
127 	    if (obj instanceof Object[]) {
128 		result.add(recAsList((Object[]) obj));
129 	    } else {
130 		result.add(obj);		 
131 	    }
132 	}
133 	// for (int i = 0; i < array.length; i++) {
134 	//     if (array[i] instanceof Object[]) {
135 	// 	result.add(recAsList((Object[]) array[i]));
136 	//     } else {
137 	// 	result.add(array[i]);		 
138 	//     }
139 	// }
140 	return result;
141     }
142 
143     /**
144      * Converts <code>source</code> 
145      * which is typically an array, 
146      * recursively into an nested {@link java.util.List} 
147      * with the given atomic entry type using the specified caster. 
148      * Note that if <code>source</code> is not an array, 
149      * it must be compatible with <code>cls</code> 
150      * up to equivalence of basic classes and their wrappers 
151      * and up to subclassing. 
152      *
153      * @param source 
154      *    an arbitrary <code>Object</code>, 
155      *    but typically an array as e.g. <code>Object[][]</code> 
156      *    or <code>double[]</code>. 
157      * @param cls 
158      *    Up to compatibility defined by <code>caster</code>, 
159      *    the type of the entries of the return value. 
160      *    Recursive conversion from arrays to lists stops 
161      *    if an entry of type compatible with <code>cls</code> is found. 
162      *    <p>
163      *    Note that this may also be a primitive type 
164      *    such as <code>int</code> or an array type 
165      *    <code>Double[][][]</code> or <code>List[][][]</code> 
166      *    or even <code>int[][][]</code>. 
167      * @return 
168      *    <ul>
169      *    <li>
170      *    if <code>cls</code> and <code>source</code> 
171      *    are assignment compatible 
172      *    up to equivalence of basic classes and their wrappers, 
173      *    <code>source</code> is returned. 
174      *    <li>
175      *    if <code>cls</code> and <code>source</code> are not compatible, 
176      *    <code>source</code> must be an array; 
177      *    otherwise an exception is thrown. 
178      *    <p>
179      *    In the former case, 
180      *    a list <code>list</code> of objects is returned 
181      *    satisfying <code>list.size() == Array.getLength(source)</code> and 
182      *    <code>list.get(i) == recAsList(Array.get(source,i),cls)</code> 
183      *    for all valid indices <code>i</code>. 
184      *    <p>
185      *    Note that the return value 
186      *    is either the result of a casting process or a list. 
187      *    In the latter case its entries are either lists themselves 
188      *    or again the result of a casting and so on. 
189      *    Clearly its atomic entries are always <code>Object</code>s 
190      *    even when starting with sources 
191      *    of type <code>int[]</code> for instance. 
192      *    </ul>
193      * @throws IllegalArgumentException 
194      *    if <code>source</code> is neither an array, 
195      *    nor assignment compatible with <code>cls</code> 
196      *    up to equivalence between basic types and their wrappers. 
197      *    Also if <code>source</code> <em>is</em> an array, 
198      *    and this condition holds for some component. 
199      *    This is a recursive definition. 
200      */
201     public static Object recAsList(Object source, Class<?> cls) {
202 	return recAsList(source, cls, Caster.BASIC_TYPES);
203     }
204 
205     /**
206      * Converts <code>source</code> 
207      * which is typically an array, 
208      * recursively into an nested {@link java.util.List} 
209      * with the given atomic entry type using the specified caster. 
210      * Note that if <code>source</code> is not an array, 
211      * it must be compatible with <code>cls</code> 
212      * with respect to <code>caster</code>. 
213      *
214      * @param source 
215      *    an arbitrary <code>Object</code>, 
216      *    but typically an array as e.g. <code>Object[][]</code> 
217      *    or <code>double[]</code>. 
218      * @param cls 
219      *    Up to compatibility defined by <code>caster</code>, 
220      *    the type of the entries of the return value. 
221      *    Recursive conversion from arrays to lists stops 
222      *    if an entry of type compatible with <code>cls</code> is found. 
223      *    <p>
224      *    Note that this may also be a primitive type 
225      *    such as <code>int</code> or an array type 
226      *    <code>Double[][][]</code> or <code>List[][][]</code> 
227      *    or even <code>int[][][]</code>. 
228      * @param caster 
229      *    performs the conversion of the top-level elements 
230      *    of the <code>source</code>. 
231      * @return 
232      *    <ul>
233      *    <li>
234      *    if <code>cls</code> and <code>source</code> are compatible 
235      *    (see {@link Caster#areCompatible}), 
236      *    the {@link Caster#cast cast of} <code>source</code> is returned. 
237      *    <p>
238      *    Note that compatibility is up to wrapping of elementary types 
239      *    and unwrapping of their wrappers. 
240      *    Arrays are converted to <code>List</code>s 
241      *    applying this method recursively to their entries. 
242      *    <li>
243      *    if <code>cls</code> and <code>source</code> are not compatible, 
244      *    <code>source</code> must be an array; 
245      *    otherwise an exception is thrown. 
246      *    <p>
247      *    In the former case, 
248      *    a list <code>list</code> of objects is returned 
249      *    satisfying <code>list.size() == Array.getLength(source)</code> and 
250      *    <code>list.get(i) == recAsList(Array.get(source,i),.. ,caster)</code> 
251      *    for all valid indices <code>i</code>. 
252      *    <p>
253      *    Note that the return value 
254      *    is either the result of a casting process or a list. 
255      *    In the latter case its entries are either lists themselves 
256      *    or again the result of a casting and so on. 
257      *    Clearly its atomic entries are always <code>Object</code>s 
258      *    even when starting with sources 
259      *    of type <code>int[]</code> for instance. 
260      *    </ul>
261      * @throws IllegalArgumentException 
262      *    if <code>source</code> is neither an array, 
263      *    nor compatible with <code>cls</code> 
264      *    with respect to <code>caster</code>. 
265      *    Also if <code>source</code> <em>is</em> an array, 
266      *    and this condition holds for some component. 
267      *    This is a recursive definition. 
268      */
269     public static Object recAsList(Object source, Class<?> cls, Caster caster) {
270 
271 	/// ***** problem: 
272 	// what about double[][][]? --- wrong caster?!? 
273 	// should use: Class compType = cls.getComponentType();
274 	if (caster.areCompatible(cls, source)) {
275 	    // Here, either source == null || cls.isInstance(source) 
276 	    // or source wraps something of type cls. 
277 	    return caster.cast(source);
278 	}
279 	// Here, source is not compatible with cls. 
280 
281 	if (!source.getClass().isArray()) {
282 	    throw new IllegalArgumentException
283 		("Found incompatible types: " + source + " is no array. ");
284 	}
285 	// Here, source is an array and cls.isArray(). 
286 
287 	List<Object> result = new ArrayList<Object>();
288 
289 	for (int i = 0; i < Array.getLength(source); i++) {
290 	    // automatic wrapping of primitive objects if needed. 
291 	    result.add(recAsList(Array.get(source, i), 
292 				 cls, 
293 				 caster));
294 	}
295 	return result;
296     }
297 
298     // /**
299     //  * Returns the class of an array with the given type of atomic entry 
300     //  * and with the given dimension (dimension in the mathematical sense). 
301     //  *
302     //  * @param elementCls 
303     //  *    The class of the element of the array class to be returned. 
304     //  * @param dim 
305     //  *    The dimension of the array; has to be non-negative. 
306     //  * @return 
307     //  *    The class of the array 
308     //  *    <code>new (elementCls)[]...dim...[]</code>. 
309     //  */
310     // public static Class<?> getArrayCls(Class<?> elementCls, int dim) {
311     // 	Class<?> result = elementCls;
312     // 	for (int i = 0; i < dim; i++) {
313     // 	    result = Array.newInstance(result, 0).getClass();
314     // 	}
315     // 	return result;
316     // }
317 
318     // ***** not yet ok 
319     // public static Class<?> getArrayWrapperCls(Class<?> cls) {
320 
321     // 	if (cls.isArray()) {
322     // 	    return getArrayWrapperCls(cls.getComponentType());
323     // 	}
324     // 	// Here, cls is no array class. 
325     // 	return BasicTypesCompatibilityChecker.getWrapperCls(cls);
326     // }
327 
328     /**
329      * Returns an empty array with type like <code>elemArray</code> 
330      * with basic type replaced by its wrapper. 
331      *
332      * @param elemArray 
333      *    a non-null array with elementary entry type 
334      *    such as <code>double[][][]</code>. 
335      * @return 
336      *    an empty array with type like <code>elemArray</code> 
337      *    with basic type replaced by its wrapper. 
338      *    For example 
339      *    <code>createWrappedEmptyArray(new int[][][] {....})</code> 
340      *    yields <code>new Integer[][][] {}</code>. 
341      * @throws IllegalArgumentException 
342      *    if <code>elemArray</code> is not an array 
343      *    or if its entry type is not elementary 
344      *    as e.g. for <code>new Integer(0)</code> 
345      *    or for <code>new Integer[][] {}</code>. 
346      * @throws NullPointerException 
347      *    if <code>elemArray</code> is <code>null</code>
348      */
349     private static Object[] createWrappedEmptyArray(Object elemArray) {
350 
351 	int counter = 0;
352 	Class<?> type = elemArray.getClass();
353 	assert type != null;
354 	while (type.isArray()) {
355 	    counter++;
356 	    type = type.getComponentType();
357 	}
358 	assert !type.isArray();
359 	assert counter > 0; // if not, elemArray is no array or overflow 
360 
361 	// throws IllegalArgumentException if type is not primitive or void 
362 	Class<?> wrapperCls = BasicTypesCompatibilityChecker
363 	    .getWrapperCls(type, false);
364 	assert wrapperCls != null && wrapperCls != Void.TYPE;
365 
366 	Object result = Array.newInstance(wrapperCls, 0);
367 	while (counter > 1) {
368 	    counter--;
369 	    // no exception because class is neither null nor Void.TYPE 
370 	    result = Array.newInstance(result.getClass(), 0);
371 	}
372 	return (Object[]) result;
373     }
374 
375     /**
376      * Returns an empty array with type like <code>wrappedArray</code> 
377      * with basic type replaced by its wrapper. 
378      *
379      * @param wrappedArray 
380      *    a non-null array with wrapper entry type 
381      *    such as <code>Double[][][]</code>. 
382      * @return 
383      *    an empty array with type like <code>wrapperArray</code> 
384      *    with basic type replaced by its wrapper. 
385      *    For example 
386      *    <code>createUnWrappedEmptyArray(new Integer[][][] {....})</code> 
387      *    yields <code>new int[][][] {}</code>. 
388      * @throws IllegalArgumentException 
389      *    if the entry type of <code>wrappedArray</code> is no wrapper type 
390      *    as e.g. for <code>new int[][] {}</code>.  
391      */
392     private static Object createUnWrappedEmptyArray(Object[] wrappedArray) {
393 
394 	int counter = 0;
395 	Class<?> type = wrappedArray.getClass();
396 	assert type != null;
397 	while (type.isArray()) {
398 	    counter++;
399 	    type = type.getComponentType();
400 	}
401 	assert !type.isArray();
402 	assert counter > 0; // except if overflow 
403 	
404 	// throws IllegalArgumentException 
405 	// if type is void or doesn't wrap a primitive type
406 	Class<?> wrappedCls = BasicTypesCompatibilityChecker
407 	    .getWrappedCls(type, false);
408 	assert wrappedCls != null && wrappedCls != Void.TYPE;
409 
410 	Object result = Array.newInstance(wrappedCls, 0);
411 	while (counter > 1) {
412 	    counter--;
413 	    // no exception because class is neither null or Void.TYPE 
414 	    result = Array.newInstance(result.getClass(), 0);
415 	}
416 	return result;
417     }
418 
419     /**
420      * Returns an array which corresponds with the given one 
421      * except that the entries are wrapped. 
422      *
423      * @param elemArray 
424      *    an array with elementary component type 
425      *    as e.g. <code>new int[][] {}</code>. 
426      *    May also be <code>null</code>. 
427      * @return 
428      *    <code>null</code> if <code>elemArray == null</code>. 
429      *    an array with the same length as <code>elemArray</code>. 
430      *    The type of the components is the wrapper type 
431      *    of the type of the components of <code>elemArray</code>. 
432      *    Also the entries are those of <code>elemArray</code> 
433      *    just wrapped. 
434      * @throws IllegalArgumentException
435      *    if <code>elemArray</code> is not an array 
436      *    or if its entry type is not elementary 
437      *    as e.g. for <code>new Integer(0)</code> 
438      *    or for <code>new Integer[][] {}</code>.  
439      */
440     public static Object[] wrapArray(Object elemArray) {
441 
442 	if (elemArray == null) {
443 	    return null;
444 	}
445 	assert elemArray != null;
446 
447 	Class<?> arrCls = elemArray.getClass();
448 	if (!arrCls.isArray()) {
449 	    throw new IllegalArgumentException
450 		("Required an array; found " + elemArray + ". ");
451 	}
452 	assert arrCls.isArray();
453 
454 	int len = Array.getLength(elemArray); // no exception 
455 
456 	// Here, elemArray is an array and so compType is not null. 
457 	Class<?> compType = arrCls.getComponentType();
458 	if (compType.isPrimitive()) {
459 	    // Here, the entry type of elemArray is primitive, 
460 	    // e.g. elemArray has type int[]. 
461 	    Class<?> compWrapperType = BasicTypesCompatibilityChecker
462 		.getWrapperCls(compType, false);
463 	    Object[] result = (Object[]) 
464 		Array.newInstance(compWrapperType, len);
465 	    for (int i = 0; i < len; i++) {
466 		// Automatically wrapped. 
467 		result[i] = Array.get(elemArray, i);
468 	    }
469 	    return result;
470 	} else {
471 	    // Here, the entry type is not primitive. 
472 	    if (len == 0) {
473 		return createWrappedEmptyArray(elemArray);
474 	    }
475 	    Object[] wrap0th = wrapArray(Array.get(elemArray, 0));
476 	    Object[] result = (Object[])
477 		Array.newInstance(wrap0th.getClass(), len);
478 	    result[0] = wrap0th;
479 	    for (int i = 1; i < len; i++) {
480 		// wrapped recursively 
481 		result[i] = wrapArray(Array.get(elemArray, i));
482 	    }
483 	    return result;
484 	}
485     }
486 
487     /**
488      * Converts an array of <code>Double</code>s 
489      * into an array of according <code>double</code>s. 
490      */
491     public static double[] toPrimitive(Double[] arr) {
492 	double[] res = new double[arr.length];
493 	for (int i = 0; i < arr.length; i++) {
494 	    res[i] = arr[i];
495 	}
496 	return res;
497     }
498 
499     /**
500      * Converts an array of <code>Float</code>s 
501      * into an array of according <code>float</code>s. 
502      */
503     public static float[] toPrimitive(Float[] arr) {
504 	float[] res = new float[arr.length];
505 	for (int i = 0; i < arr.length; i++) {
506 	    res[i] = arr[i];
507 	}
508 	return res;
509     }
510 
511     /**
512      * Converts an array of <code>Long</code>s 
513      * into an array of according <code>long</code>s. 
514      */
515     public static long[] toPrimitive(Long[] arr) {
516 	long[] res = new long[arr.length];
517 	for (int i = 0; i < arr.length; i++) {
518 	    res[i] = arr[i];
519 	}
520 	return res;
521     }
522 
523     /**
524      * Converts an array of <code>Integer</code>s 
525      * into an array of according <code>int</code>s. 
526      */
527     public static int[] toPrimitive(Integer[] arr) {
528 	int[] res = new int[arr.length];
529 	for (int i = 0; i < arr.length; i++) {
530 	    res[i] = arr[i];
531 	}
532 	return res;
533     }
534 
535     /**
536      * Converts an array of <code>Short</code>s 
537      * into an array of according <code>short</code>s. 
538      */
539     public static short[] toPrimitive(Short[] arr) {
540 	short[] res = new short[arr.length];
541 	for (int i = 0; i < arr.length; i++) {
542 	    res[i] = arr[i];
543 	}
544 	return res;
545     }
546 
547     /**
548      * Converts an array of <code>Byte</code>s 
549      * into an array of according <code>byte</code>s. 
550      */
551     public static byte[] toPrimitive(Byte[] arr) {
552 	byte[] res = new byte[arr.length];
553 	for (int i = 0; i < arr.length; i++) {
554 	    res[i] = arr[i];
555 	}
556 	return res;
557     }
558 
559     /**
560      * Converts an array of <code>Boolean</code>s 
561      * into an array of according <code>boolean</code>s. 
562      */
563     public static boolean[] toPrimitive(Boolean[] arr) {
564 	boolean[] res = new boolean[arr.length];
565 	for (int i = 0; i < arr.length; i++) {
566 	    res[i] = arr[i];
567 	}
568 	return res;
569     }
570 
571     /**
572      * Converts an array of <code>Character</code>s 
573      * into an array of according <code>char</code>s. 
574      */
575     public static char[] toPrimitive(Character[] arr) {
576 	char[] res = new char[arr.length];
577 	for (int i = 0; i < arr.length; i++) {
578 	    res[i] = arr[i];
579 	}
580 	return res;
581     }
582 
583     /**
584      * Returns an array which corresponds with the given one 
585      * except that the entries are unwrapped. 
586      *
587      * @param wrappedArray 
588      *    an array with a wrapper as component type 
589      *    as e.g. <code>new Integer[][] {}</code>. 
590      *    May also be <code>null</code>. 
591      * @return 
592      *    <code>null</code> if <code>wrappedArray == null</code>. 
593      *    an array with the same length as <code>wrappedArray</code>. 
594      *    The type of the components is the wrapped elementary type 
595      *    of the type of the components of <code>wrappedArray</code>. 
596      *    Also the entries are those of <code>wrappedArray</code> 
597      *    just unwrapped. 
598      * @throws IllegalArgumentException
599      *    if the entry type of <code>wrappedArray</code> is no wrapper 
600      *    as e.g. for <code>new int[][] {}</code> and for 
601      *    <code>new Object[][] {}</code>.  
602      */
603     public static Object unWrapArray(Object[] wrappedArray) {
604 
605 	if (wrappedArray == null) {
606 	    return null;
607 	}
608 	
609 	int len = wrappedArray.length;
610 	Class<?> compType = wrappedArray.getClass().getComponentType();
611 	if (BasicTypesCompatibilityChecker.wrapsPrimitive(compType)) {
612 	    // Here, the entry type of elemArray is a wrapper, 
613 	    // e.g. wrappedArray has type Integer[]. 
614 	    Class<?> compWrappedType = BasicTypesCompatibilityChecker
615 		.getWrappedCls(compType, false);
616 	    Object result = Array.newInstance(compWrappedType, len);
617 	    for (int i = 0; i < len; i++) {
618 		// Automatically unwrapped. 
619 		Array.set(result, i, wrappedArray[i]);
620 	    }
621 	    return result;
622 	} else {
623 	    // Here, the entry type is not a wrapper. 
624 	    if (len == 0) {
625 		// Here, elemArray is at least two dimensional, e.g. int[][0] 
626 		return createUnWrappedEmptyArray(wrappedArray);
627 	    }
628 	    if (!compType.isArray()) {
629 		// Here, component type is neither array nor component. 
630 		 throw new IllegalArgumentException
631 		     ("Expected array with wrapper type entries; found " + 
632 		      Arrays.asList(wrappedArray) + ". ");
633 	    }
634 	    // Here, compType is an array type. 
635 	    Object unWrap0th = unWrapArray((Object[]) wrappedArray[0]);
636 	    Object[] result = (Object[]) Array
637 		.newInstance(unWrap0th.getClass(), len);
638 	    result[0] = unWrap0th;
639 	    for (int i = 1; i < len; i++) {
640 		result[i] = unWrapArray((Object[]) wrappedArray[i]);
641 	    }
642 	    return result;
643 	}
644     }
645 
646     /**
647      * Comparator class 
648      * which implements a kind of lexical ordering on arrays 
649      * based on the ordering of the components 
650      * defined by <code>atomic</code>. 
651      *
652      * @param <O>
653      *    Some object type to be compared. 
654      */
655     static class ArrayComparator<O> implements Comparator<O[]> {
656 
657 	/**
658 	 * A <code>Comparator</code> for components of an array. 
659 	 * This is allocated by the constructor 
660 	 * {@link #ArrayComparator(Comparator)}. 
661 	 */
662 	private final Comparator<Object> atomic;
663 
664 	/**
665 	 * Creates a new <code>ArrayComparator</code> 
666 	 * to compare two object-arrays <!-- **** not so good --> 
667 	 * by lexical ordering. 
668 	 * Here, the orderin of the components 
669 	 * is defined by <code>atomic</code>. 
670 	 *
671 	 * @param atomic 
672 	 *    a <code>Comparator</code> for components of an array. 
673 	 */
674 	ArrayComparator(Comparator<Object> atomic) {
675 	    this.atomic = atomic;
676 	}
677 
678 	/**
679 	 * Describe <code>compare</code> method here.
680 	 *
681 	 * @param arr1 
682 	 *    an <code>Object[]</code> object. 
683 	 *    The components <code>o1[i]</code> and <code>o2[i]</code> 
684 	 *    must be pairwise comparable with respect to {@link #atomic} 
685 	 *    provided both <code>o1[i]</code> and <code>o2[i]</code> exist. 
686 	 * @param arr2 
687 	 *    an <code>Object[]</code> object. 
688 	 *    The components <code>o1[i]</code> and <code>o2[i]</code> 
689 	 *    must be pairwise comparable with respect to {@link #atomic} 
690 	 *    provided both <code>o1[i]</code> and <code>o2[i]</code> exist. 
691 	 * @return 
692 	 *    <ul>
693 	 *    <li><code>0</code>
694 	 *    if and only if <code>o1.length == o2.length</code> 
695 	 *    and <code>atomic.compare(o1[i], o2[i]) == 0</code> 
696 	 *    for all indices <code>i</code>. 
697 	 *    Hence this comparator is consistent with equals 
698 	 *    if and only if this is true for {@link #atomic}. 
699 	 *
700 	 *    <li><code>-1</code> resp.<code>1</code> 
701 	 *    if <code>o1</code> is a true prefix of <code>o2</code> 
702 	 *    res. the other way round. 
703 	 *
704 	 *    <li><code>atomic.compare(o1[i], o2[i])</code> 
705 	 *    where <code>i</code> is the lowest index such that 
706 	 *    <code>atomic.compare(o1[i], o2[i]) != 0</code>. 
707 	 *    (Provided such an index in the common range exists. )
708 	 *    </ul>
709 	 * @throws NullPointerException 
710 	 *    if one of the arguments is <code>null</code>. 
711 	 * @throws ClassCastException 
712 	 *    if one of the arguments is no <code>Object[]</code>. 
713 	 *    in particular for type <code>int[]</code>. 
714 	 */
715 	public int compare(Object[] arr1, Object[] arr2) {
716 	    // throws NullPointerException if one of the arguments is null 
717 	    int minLen = Math.min(arr1.length, arr2.length);
718 	    int result;
719 	    for (int i = 0; i < minLen; i++) {
720 		result = this.atomic.compare(arr1[i], arr2[i]);
721 		if (result != 0) {
722 		    return result;
723 		}
724 	    } // end of for ()
725 	    return arr1.length - arr2.length;
726 	}
727 
728     } // class ArrayComparator 
729 
730     /**
731      * Returns a comparator of the class {@link ArrayComparator} 
732      * which implements a kind of lexical ordering on arrays 
733      * based on the ordering of the components 
734      * defined by <code>atomic</code>. 
735      *
736      * @param atomic 
737      *    a <code>Comparator</code> for the components of arrays. 
738      * @return 
739      *    a <code>Comparator</code> for arrays. 
740      */
741     public 
742 	static Comparator<Object[]> getComparator(Comparator<Object> atomic) {
743 	return new ArrayComparator<Object>(atomic);
744     }
745 }