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 < 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 }