View Javadoc

1   /* ====================================================================
2    * The Apache Software License, Version 1.1
3    *
4    * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
5    * reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice, this list of conditions and the following disclaimer.
13   *
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in
16   *    the documentation and/or other materials provided with the
17   *    distribution.
18   *
19   * 3. The end-user documentation included with the redistribution, if
20   *    any, must include the following acknowledgement:
21   *       "This product includes software developed by the
22   *        Apache Software Foundation (http://www.apache.org/)."
23   *    Alternately, this acknowledgement may appear in the software itself,
24   *    if and wherever such third-party acknowledgements normally appear.
25   *
26   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
27   *    Foundation" must not be used to endorse or promote products derived
28   *    from this software without prior written permission. For written
29   *    permission, please contact apache@apache.org.
30   *
31   * 5. Products derived from this software may not be called "Apache"
32   *    nor may "Apache" appear in their names without prior written
33   *    permission of the Apache Software Foundation.
34   *
35   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46   * SUCH DAMAGE.
47   * ====================================================================
48   *
49   * This software consists of voluntary contributions made by many
50   * individuals on behalf of the Apache Software Foundation.  For more
51   * information on the Apache Software Foundation, please see
52   * <http://www.apache.org/>.
53   */
54  package net.sf.classifier4J.util;
55  
56  import java.lang.reflect.AccessibleObject;
57  import java.lang.reflect.Field;
58  import java.lang.reflect.Modifier;
59  
60  /***
61   * <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
62   *
63   * <p>Originally from the Apache commons-lang package</p> 
64   *
65   * <p> This class provides methods to build a good equals method for any
66   * class. It follows rules laid out in
67   * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
68   * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
69   * <code>floats</code>, and arrays can be tricky. Also, making sure that
70   * <code>equals()</code> and <code>hashCode()</code> are consistent can be
71   * difficult.</p>
72   *
73   * <p>Two Objects that compare as equals must generate the same hash code,
74   * but two Objects with the same hash code do not have to be equal.</p>
75   *
76   * <p>All relevant fields should be included in the calculation of equals.
77   * Derived fields may be ignored. In particular, any field used in
78   * generating a hash code must be used in the equals method, and vice
79   * versa.</p>
80   *
81   * <p>Typical use for the code is as follows:</p>
82   * <pre>
83   * public boolean equals(Object o) {
84   *   if ( !(o instanceof MyClass) ) {
85   *    return false;
86   *   }
87   *  MyClass rhs = (MyClass) o;
88   *  return new EqualsBuilder()
89   *                 .appendSuper(super.equals(o))
90   *                 .append(field1, rhs.field1)
91   *                 .append(field2, rhs.field2)
92   *                 .append(field3, rhs.field3)
93   *                 .isEquals();
94   *  }
95   * </pre>
96   *
97   * <p> Alternatively, there is a method that uses reflection to determine
98   * the fields to test. Because these fields are usually private, the method,
99   * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
100  * change the visibility of the fields. This will fail under a security
101  * manager, unless the appropriate permissions are set up correctly. It is
102  * also slower than testing explicitly.</p>
103  *
104  * <p> A typical invocation for this method would look like:</p>
105  * <pre>
106  * public boolean equals(Object o) {
107  *   return EqualsBuilder.reflectionEquals(this, o);
108  * }
109  * </pre>
110  *
111  * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
112  * @author Stephen Colebourne
113  * @author Gary Gregory
114  * @author Pete Gieser
115  * @since 1.0
116  * @version $Id: EqualsBuilder.java,v 1.1 2005/02/04 05:30:28 nicklothian Exp $
117  */
118 public class EqualsBuilder {
119     /***
120      * If the fields tested are equals.
121      */
122     private boolean isEquals;
123 
124     /***
125      * <p>Constructor for EqualsBuilder.</p>
126      *
127      * <p>Starts off assuming that equals is <code>true</code>.</p>
128      * @see java.lang.Object#equals
129      */
130     public EqualsBuilder() {
131         super();
132         isEquals = true;
133     }
134 
135     //-------------------------------------------------------------------------
136 
137     /***
138      * <p>This method uses reflection to determine if the two <code>Object</code>s
139      * are equal.</p>
140      *
141      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
142      * fields. This means that it will throw a security exception if run under
143      * a security manager, if the permissions are not set up correctly. It is also
144      * not as efficient as testing explicitly.</p>
145      *
146      * <p>Transient members will be not be tested, as they are likely derived
147      * fields, and not part of the value of the Object.</p>
148      *
149      * <p>Static fields will not be tested. Superclass fields will be included.</p>
150      *
151      * @param lhs  <code>this</code> object
152      * @param rhs  the other object
153      * @return <code>true</code> if the two Objects have tested equals.
154      */
155     public static boolean reflectionEquals(Object lhs, Object rhs) {
156         return reflectionEquals(lhs, rhs, false, null);
157     }
158 
159     /***
160      * <p>This method uses reflection to determine if the two <code>Object</code>s
161      * are equal.</p>
162      *
163      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
164      * fields. This means that it will throw a security exception if run under
165      * a security manager, if the permissions are not set up correctly. It is also
166      * not as efficient as testing explicitly.</p>
167      *
168      * <p>If the TestTransients parameter is set to <code>true</code>, transient
169      * members will be tested, otherwise they are ignored, as they are likely
170      * derived fields, and not part of the value of the <code>Object</code>.</p>
171      *
172      * <p>Static fields will not be tested. Superclass fields will be included.</p>
173      *
174      * @param lhs  <code>this</code> object
175      * @param rhs  the other object
176      * @param testTransients  whether to include transient fields
177      * @return <code>true</code> if the two Objects have tested equals.
178      */
179     public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) {
180         return reflectionEquals(lhs, rhs, testTransients, null);
181     }
182 
183     /***
184      * <p>This method uses reflection to determine if the two <code>Object</code>s
185      * are equal.</p>
186      *
187      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
188      * fields. This means that it will throw a security exception if run under
189      * a security manager, if the permissions are not set up correctly. It is also
190      * not as efficient as testing explicitly.</p>
191      *
192      * <p>If the testTransients parameter is set to <code>true</code>, transient
193      * members will be tested, otherwise they are ignored, as they are likely
194      * derived fields, and not part of the value of the <code>Object</code>.</p>
195      *
196      * <p>Static fields will not be included. Superclass fields will be appended
197      * up to and including the specified superclass. A null superclass is treated
198      * as java.lang.Object.</p>
199      *
200      * @param lhs  <code>this</code> object
201      * @param rhs  the other object
202      * @param testTransients  whether to include transient fields
203      * @param reflectUpToClass  the superclass to reflect up to (inclusive),
204      *  may be <code>null</code>
205      * @return <code>true</code> if the two Objects have tested equals.
206      * @since 2.0
207      */
208     public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass) {
209         if (lhs == rhs) {
210             return true;
211         }
212         if (lhs == null || rhs == null) {
213             return false;
214         }
215         // Find the leaf class since there may be transients in the leaf 
216         // class or in classes between the leaf and root.
217         // If we are not testing transients or a subclass has no ivars, 
218         // then a subclass can test equals to a superclass.
219         Class lhsClass = lhs.getClass();
220         Class rhsClass = rhs.getClass();
221         Class testClass;
222         if (lhsClass.isInstance(rhs)) {
223             testClass = lhsClass;
224             if (!rhsClass.isInstance(lhs)) {
225                 // rhsClass is a subclass of lhsClass
226                 testClass = rhsClass;
227             }
228         } else if (rhsClass.isInstance(lhs)) {
229             testClass = rhsClass;
230             if (!lhsClass.isInstance(rhs)) {
231                 // lhsClass is a subclass of rhsClass
232                 testClass = lhsClass;
233             }
234         } else {
235             // The two classes are not related.
236             return false;
237         }
238         EqualsBuilder equalsBuilder = new EqualsBuilder();
239         try {
240             reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
241             while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
242                 testClass = testClass.getSuperclass();
243                 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
244             }
245         } catch (IllegalArgumentException e) {
246             // In this case, we tried to test a subclass vs. a superclass and
247             // the subclass has ivars or the ivars are transient and 
248             // we are testing transients.
249             // If a subclass has ivars that we are trying to test them, we get an
250             // exception and we know that the objects are not equal.
251             return false;
252         }
253         return equalsBuilder.isEquals();
254     }
255 
256     /***
257      * <p>Appends the fields and values defined by the given object of the
258      * given Class.</p>
259      * 
260      * @param lhs  the left hand object
261      * @param rhs  the right hand object
262      * @param clazz  the class to append details of
263      * @param builder  the builder to append to
264      * @param useTransients  whether to test transient fields
265      */
266     private static void reflectionAppend(
267         Object lhs,
268         Object rhs,
269         Class clazz,
270         EqualsBuilder builder,
271         boolean useTransients) {
272         Field[] fields = clazz.getDeclaredFields();
273         AccessibleObject.setAccessible(fields, true);
274         for (int i = 0; i < fields.length && builder.isEquals; i++) {
275             Field f = fields[i];
276             if ((f.getName().indexOf('$') == -1)
277                 && (useTransients || !Modifier.isTransient(f.getModifiers()))
278                 && (!Modifier.isStatic(f.getModifiers()))) {
279                 try {
280                     builder.append(f.get(lhs), f.get(rhs));
281                 } catch (IllegalAccessException e) {
282                     //this can't happen. Would get a Security exception instead
283                     //throw a runtime exception in case the impossible happens.
284                     throw new InternalError("Unexpected IllegalAccessException");
285                 }
286             }
287         }
288     }
289 
290     //-------------------------------------------------------------------------
291 
292     /***
293      * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
294      *
295      * @param superEquals  the result of calling <code>super.equals()</code>
296      * @return EqualsBuilder - used to chain calls.
297      * @since 2.0
298      */
299     public EqualsBuilder appendSuper(boolean superEquals) {
300         if (isEquals == false) {
301             return this;
302         }
303         isEquals = superEquals;
304         return this;
305     }
306 
307     //-------------------------------------------------------------------------
308 
309     /***
310      * <p>Test if two <code>Object</code>s are equal using their
311      * <code>equals</code> method.</p>
312      *
313      * @param lhs  the left hand object
314      * @param rhs  the right hand object
315      * @return EqualsBuilder - used to chain calls.
316      */
317     public EqualsBuilder append(Object lhs, Object rhs) {
318         if (isEquals == false) {
319             return this;
320         }
321         if (lhs == rhs) {
322             return this;
323         }
324         if (lhs == null || rhs == null) {
325             isEquals = false;
326             return this;
327         }
328         Class lhsClass = lhs.getClass();
329         if (!lhsClass.isArray()) {
330             //the simple case, not an array, just test the element
331             isEquals = lhs.equals(rhs);
332         } else {
333             //'Switch' on type of array, to dispatch to the correct handler
334             // This handles multi dimensional arrays
335             if (lhs instanceof long[]) {
336                 append((long[]) lhs, (long[]) rhs);
337             } else if (lhs instanceof int[]) {
338                 append((int[]) lhs, (int[]) rhs);
339             } else if (lhs instanceof short[]) {
340                 append((short[]) lhs, (short[]) rhs);
341             } else if (lhs instanceof char[]) {
342                 append((char[]) lhs, (char[]) rhs);
343             } else if (lhs instanceof byte[]) {
344                 append((byte[]) lhs, (byte[]) rhs);
345             } else if (lhs instanceof double[]) {
346                 append((double[]) lhs, (double[]) rhs);
347             } else if (lhs instanceof float[]) {
348                 append((float[]) lhs, (float[]) rhs);
349             } else if (lhs instanceof boolean[]) {
350                 append((boolean[]) lhs, (boolean[]) rhs);
351             } else {
352                 // Not an array of primitives
353                 append((Object[]) lhs, (Object[]) rhs);
354             }
355         }
356         return this;
357     }
358 
359     /***
360      * <p>Test if two <code>long</code>s are equal.</p>
361      *
362      * @param lhs  the left hand <code>long</code>
363      * @param rhs  the right hand <code>long</code>
364      * @return EqualsBuilder - used to chain calls.
365      */
366     public EqualsBuilder append(long lhs, long rhs) {
367         if (isEquals == false) {
368             return this;
369         }
370         isEquals = (lhs == rhs);
371         return this;
372     }
373 
374     /***
375      * <p>Test if two <code>int</code>s are equal.</p>
376      *
377      * @param lhs  the left hand <code>int</code>
378      * @param rhs  the right hand <code>int</code>
379      * @return EqualsBuilder - used to chain calls.
380      */
381     public EqualsBuilder append(int lhs, int rhs) {
382         if (isEquals == false) {
383             return this;
384         }
385         isEquals = (lhs == rhs);
386         return this;
387     }
388 
389     /***
390      * <p>Test if two <code>short</code>s are equal.</p>
391      *
392      * @param lhs  the left hand <code>short</code>
393      * @param rhs  the right hand <code>short</code>
394      * @return EqualsBuilder - used to chain calls.
395      */
396     public EqualsBuilder append(short lhs, short rhs) {
397         if (isEquals == false) {
398             return this;
399         }
400         isEquals = (lhs == rhs);
401         return this;
402     }
403 
404     /***
405      * <p>Test if two <code>char</code>s are equal.</p>
406      *
407      * @param lhs  the left hand <code>char</code>
408      * @param rhs  the right hand <code>char</code>
409      * @return EqualsBuilder - used to chain calls.
410      */
411     public EqualsBuilder append(char lhs, char rhs) {
412         if (isEquals == false) {
413             return this;
414         }
415         isEquals = (lhs == rhs);
416         return this;
417     }
418 
419     /***
420      * <p>Test if two <code>byte</code>s are equal.</p>
421      *
422      * @param lhs  the left hand <code>byte</code>
423      * @param rhs  the right hand <code>byte</code>
424      * @return EqualsBuilder - used to chain calls.
425      */
426     public EqualsBuilder append(byte lhs, byte rhs) {
427         if (isEquals == false) {
428             return this;
429         }
430         isEquals = (lhs == rhs);
431         return this;
432     }
433 
434     /***
435      * <p>Test if two <code>double</code>s are equal by testing that the
436      * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
437      *
438      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
439      *
440      * <p>It is compatible with the hash code generated by
441      * <code>HashCodeBuilder</code>.</p>
442      *
443      * @param lhs  the left hand <code>double</code>
444      * @param rhs  the right hand <code>double</code>
445      * @return EqualsBuilder - used to chain calls.
446      */
447     public EqualsBuilder append(double lhs, double rhs) {
448         if (isEquals == false) {
449             return this;
450         }
451         return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
452     }
453 
454     /***
455      * <p>Test if two <code>float</code>s are equal byt testing that the
456      * pattern of bits returned by doubleToLong are equal.</p>
457      *
458      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
459      *
460      * <p>It is compatible with the hash code generated by
461      * <code>HashCodeBuilder</code>.</p>
462      *
463      * @param lhs  the left hand <code>float</code>
464      * @param rhs  the right hand <code>float</code>
465      * @return EqualsBuilder - used to chain calls.
466      */
467     public EqualsBuilder append(float lhs, float rhs) {
468         if (isEquals == false) {
469             return this;
470         }
471         return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
472     }
473 
474     /***
475      * <p>Test if two <code>booleans</code>s are equal.</p>
476      *
477      * @param lhs  the left hand <code>boolean</code>
478      * @param rhs  the right hand <code>boolean</code>
479      * @return EqualsBuilder - used to chain calls.
480       */
481     public EqualsBuilder append(boolean lhs, boolean rhs) {
482         if (isEquals == false) {
483             return this;
484         }
485         isEquals = (lhs == rhs);
486         return this;
487     }
488 
489     /***
490      * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
491      *
492      * <p>This also will be called for the top level of
493      * multi-dimensional, ragged, and multi-typed arrays.</p>
494      *
495      * @param lhs  the left hand <code>Object[]</code>
496      * @param rhs  the right hand <code>Object[]</code>
497      * @return EqualsBuilder - used to chain calls.
498      */
499     public EqualsBuilder append(Object[] lhs, Object[] rhs) {
500         if (isEquals == false) {
501             return this;
502         }
503         if (lhs == rhs) {
504             return this;
505         }
506         if (lhs == null || rhs == null) {
507             isEquals = false;
508             return this;
509         }
510         if (lhs.length != rhs.length) {
511             isEquals = false;
512             return this;
513         }
514         for (int i = 0; i < lhs.length && isEquals; ++i) {
515             Class lhsClass = lhs[i].getClass();
516             if (!lhsClass.isInstance(rhs[i])) {
517                 isEquals = false; //If the types don't match, not equal
518                 break;
519             }
520             append(lhs[i], rhs[i]);
521         }
522         return this;
523     }
524 
525     /***
526      * <p>Deep comparison of array of <code>long</code>. Length and all
527      * values are compared.</p>
528      *
529      * <p>The method {@link #append(long, long)} is used.</p>
530      *
531      * @param lhs  the left hand <code>long[]</code>
532      * @param rhs  the right hand <code>long[]</code>
533      * @return EqualsBuilder - used to chain calls.
534      */
535     public EqualsBuilder append(long[] lhs, long[] rhs) {
536         if (isEquals == false) {
537             return this;
538         }
539         if (lhs == rhs) {
540             return this;
541         }
542         if (lhs == null || rhs == null) {
543             isEquals = false;
544             return this;
545         }
546         if (lhs.length != rhs.length) {
547             isEquals = false;
548             return this;
549         }
550         for (int i = 0; i < lhs.length && isEquals; ++i) {
551             append(lhs[i], rhs[i]);
552         }
553         return this;
554     }
555 
556     /***
557      * <p>Deep comparison of array of <code>int</code>. Length and all
558      * values are compared.</p>
559      *
560      * <p>The method {@link #append(int, int)} is used.</p>
561      *
562      * @param lhs  the left hand <code>int[]</code>
563      * @param rhs  the right hand <code>int[]</code>
564      * @return EqualsBuilder - used to chain calls.
565      */
566     public EqualsBuilder append(int[] lhs, int[] rhs) {
567         if (isEquals == false) {
568             return this;
569         }
570         if (lhs == rhs) {
571             return this;
572         }
573         if (lhs == null || rhs == null) {
574             isEquals = false;
575             return this;
576         }
577         if (lhs.length != rhs.length) {
578             isEquals = false;
579             return this;
580         }
581         for (int i = 0; i < lhs.length && isEquals; ++i) {
582             append(lhs[i], rhs[i]);
583         }
584         return this;
585     }
586 
587     /***
588      * <p>Deep comparison of array of <code>short</code>. Length and all
589      * values are compared.</p>
590      *
591      * <p>The method {@link #append(short, short)} is used.</p>
592      *
593      * @param lhs  the left hand <code>short[]</code>
594      * @param rhs  the right hand <code>short[]</code>
595      * @return EqualsBuilder - used to chain calls.
596      */
597     public EqualsBuilder append(short[] lhs, short[] rhs) {
598         if (isEquals == false) {
599             return this;
600         }
601         if (lhs == rhs) {
602             return this;
603         }
604         if (lhs == null || rhs == null) {
605             isEquals = false;
606             return this;
607         }
608         if (lhs.length != rhs.length) {
609             isEquals = false;
610             return this;
611         }
612         for (int i = 0; i < lhs.length && isEquals; ++i) {
613             append(lhs[i], rhs[i]);
614         }
615         return this;
616     }
617 
618     /***
619      * <p>Deep comparison of array of <code>char</code>. Length and all
620      * values are compared.</p>
621      *
622      * <p>The method {@link #append(char, char)} is used.</p>
623      *
624      * @param lhs  the left hand <code>char[]</code>
625      * @param rhs  the right hand <code>char[]</code>
626      * @return EqualsBuilder - used to chain calls.
627      */
628     public EqualsBuilder append(char[] lhs, char[] rhs) {
629         if (isEquals == false) {
630             return this;
631         }
632         if (lhs == rhs) {
633             return this;
634         }
635         if (lhs == null || rhs == null) {
636             isEquals = false;
637             return this;
638         }
639         if (lhs.length != rhs.length) {
640             isEquals = false;
641             return this;
642         }
643         for (int i = 0; i < lhs.length && isEquals; ++i) {
644             append(lhs[i], rhs[i]);
645         }
646         return this;
647     }
648 
649     /***
650      * <p>Deep comparison of array of <code>byte</code>. Length and all
651      * values are compared.</p>
652      *
653      * <p>The method {@link #append(byte, byte)} is used.</p>
654      *
655      * @param lhs  the left hand <code>byte[]</code>
656      * @param rhs  the right hand <code>byte[]</code>
657      * @return EqualsBuilder - used to chain calls.
658      */
659     public EqualsBuilder append(byte[] lhs, byte[] rhs) {
660         if (isEquals == false) {
661             return this;
662         }
663         if (lhs == rhs) {
664             return this;
665         }
666         if (lhs == null || rhs == null) {
667             isEquals = false;
668             return this;
669         }
670         if (lhs.length != rhs.length) {
671             isEquals = false;
672             return this;
673         }
674         for (int i = 0; i < lhs.length && isEquals; ++i) {
675             append(lhs[i], rhs[i]);
676         }
677         return this;
678     }
679 
680     /***
681      * <p>Deep comparison of array of <code>double</code>. Length and all
682      * values are compared.</p>
683      *
684      * <p>The method {@link #append(double, double)} is used.</p>
685      *
686      * @param lhs  the left hand <code>double[]</code>
687      * @param rhs  the right hand <code>double[]</code>
688      * @return EqualsBuilder - used to chain calls.
689      */
690     public EqualsBuilder append(double[] lhs, double[] rhs) {
691         if (isEquals == false) {
692             return this;
693         }
694         if (lhs == rhs) {
695             return this;
696         }
697         if (lhs == null || rhs == null) {
698             isEquals = false;
699             return this;
700         }
701         if (lhs.length != rhs.length) {
702             isEquals = false;
703             return this;
704         }
705         for (int i = 0; i < lhs.length && isEquals; ++i) {
706             append(lhs[i], rhs[i]);
707         }
708         return this;
709     }
710 
711     /***
712      * <p>Deep comparison of array of <code>float</code>. Length and all
713      * values are compared.</p>
714      *
715      * <p>The method {@link #append(float, float)} is used.</p>
716      *
717      * @param lhs  the left hand <code>float[]</code>
718      * @param rhs  the right hand <code>float[]</code>
719      * @return EqualsBuilder - used to chain calls.
720      */
721     public EqualsBuilder append(float[] lhs, float[] rhs) {
722         if (isEquals == false) {
723             return this;
724         }
725         if (lhs == rhs) {
726             return this;
727         }
728         if (lhs == null || rhs == null) {
729             isEquals = false;
730             return this;
731         }
732         if (lhs.length != rhs.length) {
733             isEquals = false;
734             return this;
735         }
736         for (int i = 0; i < lhs.length && isEquals; ++i) {
737             append(lhs[i], rhs[i]);
738         }
739         return this;
740     }
741 
742     /***
743      * <p>Deep comparison of array of <code>boolean</code>. Length and all
744      * values are compared.</p>
745      *
746      * <p>The method {@link #append(boolean, boolean)} is used.</p>
747      *
748      * @param lhs  the left hand <code>boolean[]</code>
749      * @param rhs  the right hand <code>boolean[]</code>
750      * @return EqualsBuilder - used to chain calls.
751      */
752     public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
753         if (isEquals == false) {
754             return this;
755         }
756         if (lhs == rhs) {
757             return this;
758         }
759         if (lhs == null || rhs == null) {
760             isEquals = false;
761             return this;
762         }
763         if (lhs.length != rhs.length) {
764             isEquals = false;
765             return this;
766         }
767         for (int i = 0; i < lhs.length && isEquals; ++i) {
768             append(lhs[i], rhs[i]);
769         }
770         return this;
771     }
772 
773     /***
774      * <p>Return <code>true</code> if the fields that have been checked
775      * are all equal.</p>
776      *
777      * @return boolean
778      */
779     public boolean isEquals() {
780         return isEquals;
781     }
782 
783 }