Java/Class/Equals — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
|
(нет различий)
|
Текущая версия на 06:36, 1 июня 2010
Содержание
Compares two objects for equality, where either one or both objects may be null
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.Serializable;
/**
* <p>Operations on <code>Object</code>.</p>
*
* <p>This class tries to handle <code>null</code> input gracefully.
* An exception will generally not be thrown for a <code>null</code> input.
* Each method documents its behaviour in more detail.</p>
*
* @author
* @since 1.0
* @version $Id: ObjectUtils.java 594336 2007-11-12 22:54:02Z bayard $
*/
public class ObjectUtils {
/**
* <p>Singleton used as a <code>null</code> placeholder where
* <code>null</code> has another meaning.</p>
*
* <p>For example, in a <code>HashMap</code> the
* {@link java.util.HashMap#get(java.lang.Object)} method returns
* <code>null</code> if the <code>Map</code> contains
* <code>null</code> or if there is no matching key. The
* <code>Null</code> placeholder can be used to distinguish between
* these two cases.</p>
*
* <p>Another example is <code>Hashtable</code>, where <code>null</code>
* cannot be stored.</p>
*
* <p>This instance is Serializable.</p>
*/
public static final Null NULL = new Null();
/**
* <p><code>ObjectUtils</code> instances should NOT be constructed in
* standard programming. Instead, the class should be used as
* <code>ObjectUtils.defaultIfNull("a","b");</code>.</p>
*
* <p>This constructor is public to permit tools that require a JavaBean instance
* to operate.</p>
*/
public ObjectUtils() {
super();
}
// Defaulting
//-----------------------------------------------------------------------
/**
* <p>Returns a default value if the object passed is
* <code>null</code>.</p>
*
* <pre>
* ObjectUtils.defaultIfNull(null, null) = null
* ObjectUtils.defaultIfNull(null, "") = ""
* ObjectUtils.defaultIfNull(null, "zz") = "zz"
* ObjectUtils.defaultIfNull("abc", *) = "abc"
* ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
* </pre>
*
* @param object the <code>Object</code> to test, may be <code>null</code>
* @param defaultValue the default value to return, may be <code>null</code>
* @return <code>object</code> if it is not <code>null</code>, defaultValue otherwise
*/
public static Object defaultIfNull(Object object, Object defaultValue) {
return object != null ? object : defaultValue;
}
/**
* <p>Compares two objects for equality, where either one or both
* objects may be <code>null</code>.</p>
*
* <pre>
* ObjectUtils.equals(null, null) = true
* ObjectUtils.equals(null, "") = false
* ObjectUtils.equals("", null) = false
* ObjectUtils.equals("", "") = true
* ObjectUtils.equals(Boolean.TRUE, null) = false
* ObjectUtils.equals(Boolean.TRUE, "true") = false
* ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE) = true
* ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
* </pre>
*
* @param object1 the first object, may be <code>null</code>
* @param object2 the second object, may be <code>null</code>
* @return <code>true</code> if the values of both objects are the same
*/
public static boolean equals(Object object1, Object object2) {
if (object1 == object2) {
return true;
}
if ((object1 == null) || (object2 == null)) {
return false;
}
return object1.equals(object2);
}
/**
* <p>Gets the hash code of an object returning zero when the
* object is <code>null</code>.</p>
*
* <pre>
* ObjectUtils.hashCode(null) = 0
* ObjectUtils.hashCode(obj) = obj.hashCode()
* </pre>
*
* @param obj the object to obtain the hash code of, may be <code>null</code>
* @return the hash code of the object, or zero if null
* @since 2.1
*/
public static int hashCode(Object obj) {
return (obj == null) ? 0 : obj.hashCode();
}
// Identity ToString
//-----------------------------------------------------------------------
/**
* <p>Gets the toString that would be produced by <code>Object</code>
* if a class did not override toString itself. <code>null</code>
* will return <code>null</code>.</p>
*
* <pre>
* ObjectUtils.identityToString(null) = null
* ObjectUtils.identityToString("") = "java.lang.String@1e23"
* ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
* </pre>
*
* @param object the object to create a toString for, may be
* <code>null</code>
* @return the default toString text, or <code>null</code> if
* <code>null</code> passed in
*/
public static String identityToString(Object object) {
if (object == null) {
return null;
}
StringBuffer buffer = new StringBuffer();
identityToString(buffer, object);
return buffer.toString();
}
/**
* <p>Appends the toString that would be produced by <code>Object</code>
* if a class did not override toString itself. <code>null</code>
* will throw a NullPointerException for either of the two parameters. </p>
*
* <pre>
* ObjectUtils.identityToString(buf, "") = buf.append("java.lang.String@1e23"
* ObjectUtils.identityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa"
* ObjectUtils.identityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa")
* </pre>
*
* @param buffer the buffer to append to
* @param object the object to create a toString for
* @since 2.4
*/
public static void identityToString(StringBuffer buffer, Object object) {
if (object == null) {
throw new NullPointerException("Cannot get the toString of a null identity");
}
buffer.append(object.getClass().getName())
.append("@")
.append(Integer.toHexString(System.identityHashCode(object)));
}
// ToString
//-----------------------------------------------------------------------
/**
* <p>Gets the <code>toString</code> of an <code>Object</code> returning
* an empty string ("") if <code>null</code> input.</p>
*
* <pre>
* ObjectUtils.toString(null) = ""
* ObjectUtils.toString("") = ""
* ObjectUtils.toString("bat") = "bat"
* ObjectUtils.toString(Boolean.TRUE) = "true"
* </pre>
*
* @see StringUtils#defaultString(String)
* @see String#valueOf(Object)
* @param obj the Object to <code>toString</code>, may be null
* @return the passed in Object"s toString, or nullStr if <code>null</code> input
* @since 2.0
*/
public static String toString(Object obj) {
return obj == null ? "" : obj.toString();
}
/**
* <p>Gets the <code>toString</code> of an <code>Object</code> returning
* a specified text if <code>null</code> input.</p>
*
* <pre>
* ObjectUtils.toString(null, null) = null
* ObjectUtils.toString(null, "null") = "null"
* ObjectUtils.toString("", "null") = ""
* ObjectUtils.toString("bat", "null") = "bat"
* ObjectUtils.toString(Boolean.TRUE, "null") = "true"
* </pre>
*
* @see StringUtils#defaultString(String,String)
* @see String#valueOf(Object)
* @param obj the Object to <code>toString</code>, may be null
* @param nullStr the String to return if <code>null</code> input, may be null
* @return the passed in Object"s toString, or nullStr if <code>null</code> input
* @since 2.0
*/
public static String toString(Object obj, String nullStr) {
return obj == null ? nullStr : obj.toString();
}
// Null
//-----------------------------------------------------------------------
/**
* <p>Class used as a null placeholder where <code>null</code>
* has another meaning.</p>
*
* <p>For example, in a <code>HashMap</code> the
* {@link java.util.HashMap#get(java.lang.Object)} method returns
* <code>null</code> if the <code>Map</code> contains
* <code>null</code> or if there is no matching key. The
* <code>Null</code> placeholder can be used to distinguish between
* these two cases.</p>
*
* <p>Another example is <code>Hashtable</code>, where <code>null</code>
* cannot be stored.</p>
*/
public static class Null implements Serializable {
/**
* Required for serialization support. Declare serialization compatibility with Commons Lang 1.0
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 7092611880189329093L;
/**
* Restricted constructor - singleton.
*/
Null() {
super();
}
/**
* <p>Ensure singleton.</p>
*
* @return the singleton value
*/
private Object readResolve() {
return ObjectUtils.NULL;
}
}
}
Equals(Equal) Method
//: c03:EqualsMethod2.java
// From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
// www.BruceEckel.ru. See copyright notice in CopyRight.txt.
class Value {
int i;
}
public class EqualsMethod2 {
public static void main(String[] args) {
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
} ///:~
Equals Method
//: c03:EqualsMethod.java
// From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
// www.BruceEckel.ru. See copyright notice in CopyRight.txt.
public class EqualsMethod {
public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1.equals(n2));
}
} ///:~
Equivalence
//: c03:Equivalence.java
// From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
// www.BruceEckel.ru. See copyright notice in CopyRight.txt.
public class Equivalence {
static Test monitor = new Test();
public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1 == n2);
System.out.println(n1 != n2);
}
} ///:~
Equivalence ClassSet
/**
* EquivalenceClassSet.java
*
* @author bret5
* Copyright(C) 2007 bret5
*
* This is a specialized set class which groups the elements into
* equivalence classes based on the by the comparator provided at
* set creation time. Iterators created thru the standard set interface
* will return elements sorted by comparator order. Elements that
* are equivalent may be returned in any order.
*
* The class also provides a special loopIterator iteration
* which will return each element once in comparator order, then loop back
* around to the first element at the end. The loopIterator continues to be valid
* as add/remove operations are performed. If shuffleEquivalenceClasses is set,
* it will randomly shuffles the elements in each equivalence class
* every time that equivalence class is reached during iteration. If not,
* each equivalence class will be returned in the same order every time.
* shuffleEquivalenceClasses defaults to true.
*
* This Set does not allow null elements.
*
* This was written for a program that uses jdk 1.4, so it doesn"t yet use the generic style.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.ruparator;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/**
* @author bret5
*
*/
public class EquivalenceClassSet<T> extends AbstractSet<T>
{
// the list backing the class. This is a list of the
// equivalence classes - each equivalence class is a sublist
// which contains all the elements equivalent to each other.
// The sublists appear in order corresponding to the ordering
// provided by the comparator provided at set creation time.
private List m_equivalenceClasses;
private int m_size; // cached for efficiency
private Comparator m_comparator;
private ListIterator m_loopEqvClassIter; // non-null index used by the loop iterator
private List m_loopCurrentEqvClass; // ptr to current class, null ok
private ListIterator<T> m_loopItemIter; // non-null index used by the loop iterator
private final static List m_emptyList = new ArrayList(); // emptyList used for gen-ing iterators
// In order to maintain some sanity in the face of objects changing with respect to
// the comparator after being added to the set, we keep track of which class every object
// is in. This way, the behavior of contains and remove are undisturbed by changes to the
// objects.
private HashMap m_itemToClassMap;
// TODO - size is now redundant with the size of the item-class map, remove...
private int m_changeID; // supports iterator fail-fast, increment on each modification
private boolean m_shuffleEquivalenceClasses;
/*
* Class invariants:
* Individual equivalence classes may not be empty
* The cached size is equal to the sum of all items in the sublists
* The changeID increments montonically whenever the set contents are changed,
* although it does reset on a clear()
*/
public EquivalenceClassSet(Comparator<T> c)
{
super();
m_comparator = c;
m_equivalenceClasses = new LinkedList();
m_size = 0;
m_itemToClassMap = new HashMap();
resetLoopIterator();
m_changeID = 0;
m_shuffleEquivalenceClasses = true;
}
protected class OnePassIterator implements Iterator<T>
{
private int localChangeID;
private ListIterator localEqvClassIter; // class iter
private ListIterator<T> localItemIter; // item iter
protected OnePassIterator()
{
localChangeID = m_changeID;
localEqvClassIter = m_equivalenceClasses.listIterator(); // index used by the loop iterator
localItemIter = null; // null means before the next class
}
public boolean hasNext()
{
if (m_changeID != localChangeID)
{
throw new ConcurrentModificationException();
}
if (localEqvClassIter.hasNext() ||
(localItemIter != null && localItemIter.hasNext()))
{
return true;
}
return false;
}
public T next()
{
if (m_changeID != localChangeID)
{
throw new ConcurrentModificationException();
}
if (localItemIter == null || !localItemIter.hasNext())
{
localItemIter = ((List)localEqvClassIter.next()).listIterator();
}
return localItemIter.next();
}
public void remove()
{
throw new UnsupportedOperationException();
}
}
public Iterator<T> iterator()
{
return new OnePassIterator();
}
// Note that this iterator is intended to continue iteration after element addition
// and removal. Therefore we put the underlying iterators in the main class so that
// they can be adjusted/replaced when necessary
// invariants:
// if size = 0, currentEqvClassIter is null.
// if size not null, then both currentEqvClassIter and currentItemIter
// are not null.
protected class LoopIterator implements Iterator<T>
{
public boolean hasNext()
{
return ( m_size > 0 );
}
public T next()
{
assert m_loopEqvClassIter != null;
assert m_loopItemIter != null;
if (m_size <= 0)
{
throw new NoSuchElementException();
}
// first, move to a new class if necessary, resetting the item iter.
// if switching classes, shuffle.
if (!m_loopItemIter.hasNext())
{
if (!m_loopEqvClassIter.hasNext())
{
// recycle to beginning
m_loopEqvClassIter = m_equivalenceClasses.listIterator();
}
m_loopCurrentEqvClass = (List)m_loopEqvClassIter.next();
assert m_loopCurrentEqvClass.size() > 0;
if (m_shuffleEquivalenceClasses)
{
java.util.Collections.shuffle(m_loopCurrentEqvClass);
}
m_loopItemIter = m_loopCurrentEqvClass.listIterator();
}
return m_loopItemIter.next();
}
public void remove()
{
throw new UnsupportedOperationException();
}
}
/**
* The loopIterator is a special iteration for which hasNext() returns
* true if the size is greater than 0. The next() method
* traverses the equivalence classes in comparator order. Within
* each equivalence class, the items are returned randomly
* (by shuffling the elements in the equivalence class every time
* that equivalence class is reached during iteration).
*
* Iteration can be reset to the first equivalence class by using
* the resetLoopIterator method of the main class.
*
* @return the iterator
*/
public Iterator<T> loopIterator()
{
return new LoopIterator();
}
public void resetLoopIterator()
{
m_loopEqvClassIter = m_equivalenceClasses.listIterator();
m_loopCurrentEqvClass = null;
m_loopItemIter = m_emptyList.listIterator();
}
/**
* If shuffleEquivalenceClasses is set, the loopItertor will randomly shuffle
* the elements in each equivalence class every time that equivalence class
* is reached during iteration.
*
* @return the value of shuffleEquivalenceClasses
*/
public boolean isShuffleEquivalenceClasses()
{
return m_shuffleEquivalenceClasses;
}
/**
* Set the value of shuffleEquivalenceClasses.
* @see isShuffleEquivalenceClasses()
*/
public void setShuffleEquivalenceClasses(boolean shuffleEquivalenceClasses)
{
this.m_shuffleEquivalenceClasses = shuffleEquivalenceClasses;
}
/* (non-Javadoc)
* @see java.util.AbstractCollection#size()
*/
public int size()
{
return m_size;
}
/*
* Adds the argument to the collection. If the element is not already
* a member of the set, and is equivalent to the current equivalence
* class, it is added so that it will be returned before any element
* from another class is returned.
*/
public boolean add(T arg0)
{
return addPositional(arg0, true);
}
/*
* Adds the argument to the collection. If the element is not already
* a member of the set, and is equivalent to the current equivalence
* class, it is added so that it will not be returned before an element
* from another class is returned (if there are any other classes).
*/
public boolean addExpired(T arg0)
{
return addPositional(arg0, false);
}
protected boolean addPositional(Object arg0, boolean atEnd)
{
EqvPosition eqvPosition = findEqvClass(arg0);
boolean isChanged = false;
if (eqvPosition.matchingEqvClass != null)
{
int iterIdx = 0;
boolean replaceLoopItemIter = false;
if (eqvPosition.matchingEqvClass == m_loopCurrentEqvClass)
{
// we have to replace the item loop iterator for this class, so get the position
replaceLoopItemIter = true;
iterIdx = m_loopItemIter.nextIndex();
}
if (!eqvPosition.matchingEqvClass.contains(arg0))
{
if (atEnd)
{
eqvPosition.matchingEqvClass.add(arg0);
}
else
{
eqvPosition.matchingEqvClass.add(0, arg0);
iterIdx += 1;
}
isChanged = true;
if (replaceLoopItemIter)
{
m_loopItemIter = m_loopCurrentEqvClass.listIterator(iterIdx);
}
}
}
else
{
// there is no matching class, so add one
ArrayList newEqvClass = new ArrayList();
newEqvClass.add(arg0);
eqvPosition.matchingEqvClass = newEqvClass; // cache the eqv class ref for adding to map
int iterIdx, addIdx;
iterIdx = 0;
addIdx = 0;
if (m_size >= 1)
{
iterIdx = m_loopEqvClassIter.nextIndex();
addIdx = eqvPosition.eqvClassIter.nextIndex();
if (addIdx < iterIdx)
{
iterIdx += 1;
}
}
eqvPosition.eqvClassIter.add(newEqvClass);
isChanged = true;
// replace the class loop iterator
m_loopEqvClassIter = m_equivalenceClasses.listIterator(iterIdx);
// if the new class is next and the add is "expired"/(not atEnd),
// advance the iterator past the just added item
if (iterIdx == addIdx && !atEnd && !m_loopItemIter.hasNext())
{
m_loopCurrentEqvClass = (List)m_loopEqvClassIter.next();
m_loopItemIter = m_loopCurrentEqvClass.listIterator(1);
}
}
if (isChanged)
{
m_size += 1;
m_changeID += 1;
m_itemToClassMap.put(arg0, eqvPosition.matchingEqvClass);
}
return isChanged;
}
// represents the location of the equivalence class matching a value.
// returned from findEqvClass, so we only have to write that code once.
// If there is a matching class, then matchingEqvClass will be non-null.
// If not, then eqvClassIter holds the position that eqv class would have.
protected class EqvPosition
{
protected List matchingEqvClass;
protected ListIterator eqvClassIter;
}
// If there is a matching class, then matchingEqvClass will be non-null.
// If not, then eqvClassIter holds the position that eqv class would have.
protected EqvPosition findEqvClass(Object arg0)
{
EqvPosition eqvPosition = new EqvPosition();
if (m_itemToClassMap.containsKey(arg0))
{
eqvPosition.matchingEqvClass = (List)m_itemToClassMap.get(arg0);
return eqvPosition; // note that the iterator will be null.
}
eqvPosition.eqvClassIter = m_equivalenceClasses.listIterator();
while (eqvPosition.eqvClassIter.hasNext())
{
List testEqvClass = (List)eqvPosition.eqvClassIter.next();
assert testEqvClass.size() > 0;
int comparison = m_comparator.rupare(arg0, testEqvClass.get(0));
if (comparison < 0)
{
// there is no matching class, to insert before this one, return the previous position
if (eqvPosition.eqvClassIter.hasPrevious())
{
eqvPosition.eqvClassIter.previous();
}
break;
}
else if (comparison == 0)
{
eqvPosition.matchingEqvClass = testEqvClass;
return eqvPosition;
}
// and fall through to the next eqvClass
}
return eqvPosition;
}
/* (non-Javadoc)
* @see java.util.AbstractCollection#clear()
*/
public void clear()
{
m_equivalenceClasses.clear();
m_itemToClassMap.clear();
m_size = 0;
m_changeID = 0; // can reset to original state
resetLoopIterator();
}
/* (non-Javadoc)
* @see java.util.AbstractCollection#contains(java.lang.Object)
*/
public boolean contains(Object arg0)
{
EqvPosition eqvPosition = findEqvClass(arg0);
if (eqvPosition.matchingEqvClass != null &&
eqvPosition.matchingEqvClass.contains(arg0))
{
return true; // already a member, do nothing
}
return false;
}
/* (non-Javadoc)
* @see java.util.AbstractCollection#remove(java.lang.Object)
*/
public boolean remove(Object arg0)
{
assert m_size == m_itemToClassMap.size();
EqvPosition eqvPosition = findEqvClass(arg0);
return removeAtPosition(eqvPosition, arg0);
}
/* (non-Javadoc)
* @see java.util.AbstractCollection#remove(java.lang.Object)
*/
private boolean removeAtPosition(EqvPosition eqvPosition, Object arg0)
{
// when removing an object, we may have to replace the item loop iterator
// if we removed an item from the current loop class
// also, if the removal results in removal of a class, we may have to
// replace the class loop iter
boolean isChanged = false;
boolean replaceLoopItemIter = false;
if (eqvPosition.matchingEqvClass != null)
{
int itemLocationIdx = 0;
int loopNextItemIdx = 0;
int itemClassIdx = 0;
int loopNextClassIdx = 0;
itemLocationIdx = eqvPosition.matchingEqvClass.indexOf(arg0);
if (itemLocationIdx >= 0)
{
// the item is a member of this class and will be removed
isChanged = true;
if (eqvPosition.matchingEqvClass == m_loopCurrentEqvClass)
{
// we may have to replace the item loop iterator for this class, so get the position
replaceLoopItemIter = true;
loopNextItemIdx = m_loopItemIter.nextIndex();
if (itemLocationIdx < loopNextItemIdx)
{
loopNextItemIdx -= 1;
}
}
eqvPosition.matchingEqvClass.remove(arg0);
if (eqvPosition.matchingEqvClass.size() <= 0)
{
// the class is now empty, remove it
loopNextClassIdx = m_loopEqvClassIter.nextIndex();
itemClassIdx = m_equivalenceClasses.indexOf(eqvPosition.matchingEqvClass);
if (itemClassIdx < loopNextClassIdx)
{
loopNextClassIdx -= 1;
}
m_equivalenceClasses.remove(eqvPosition.matchingEqvClass);
// and replace the loop iterator, and maybe the item iterator
if (m_equivalenceClasses.size() == 0)
{
resetLoopIterator();
}
else
{
m_loopEqvClassIter = m_equivalenceClasses.listIterator(loopNextClassIdx);
if (eqvPosition.matchingEqvClass == m_loopCurrentEqvClass)
{
m_loopCurrentEqvClass = null;
m_loopItemIter = m_emptyList.listIterator();
}
}
}
else if (replaceLoopItemIter)
{
// replace the item iterator for the class
m_loopItemIter = m_loopCurrentEqvClass.listIterator(loopNextItemIdx);
}
}
}
if (isChanged)
{
m_itemToClassMap.remove(arg0);
m_size -= 1;
assert m_size >= 0;
assert m_size == m_itemToClassMap.size();
m_changeID += 1;
}
return isChanged;
}
public Comparator<T> getComparator()
{
return m_comparator;
}
/**
* Partition this set into two sets, returning the new one.
*
* The argument specifies how many elements to put in the new set. Elements will be
* chosen in comparator order. All elements put into the new set will be removed from
* this set. If the original set contained less elements than the argument, then
* after the partition the new set will contain all the elements and the original set
* will be empty.
*
* If the partition is non-trivial (that is, if the new set contains at least one
* element), then the counters for the loop iterator will be reset.
*
* @param numberToRemove number of elements to remove from the original set
*
* @return the new set
*/
public EquivalenceClassSet<T> partition(int numberToRemove)
{
EquivalenceClassSet<T> newSet = new EquivalenceClassSet<T>(m_comparator);
while (numberToRemove > 0 && m_size > 0)
{
ArrayList firstEqvClass = (ArrayList)(m_equivalenceClasses.get(0));
int sizeOfFEqvClass = firstEqvClass.size();
int numberMoved = 0;
List movedEqvClass;
if (numberToRemove >= sizeOfFEqvClass)
{
movedEqvClass = (List)m_equivalenceClasses.remove(0);
newSet.m_equivalenceClasses.add(movedEqvClass);
numberMoved = sizeOfFEqvClass;
}
else
{
// shuffle the equivalence class prior to a partial selection
if (m_shuffleEquivalenceClasses)
{
java.util.Collections.shuffle(firstEqvClass);
}
movedEqvClass = new ArrayList(firstEqvClass.subList(0, numberToRemove));
firstEqvClass.subList(0, numberToRemove).clear();
newSet.m_equivalenceClasses.add(movedEqvClass);
numberMoved = numberToRemove;
}
m_size -= numberMoved;
newSet.m_size += numberMoved;
numberToRemove -= numberMoved;
// now fix up the item to class map
Iterator iter = movedEqvClass.iterator();
while (iter.hasNext())
{
Object obj = iter.next();
m_itemToClassMap.remove(obj);
newSet.m_itemToClassMap.put(obj, movedEqvClass);
}
}
if (newSet.size() > 0)
{
newSet.resetLoopIterator();
resetLoopIterator();
m_changeID += 1;
newSet.m_changeID += 1;
}
assert m_size == m_itemToClassMap.size();
assert newSet.m_size == newSet.m_itemToClassMap.size();
return newSet;
}
/**
* In some cases, the equivalence class of an object will change. This can leave
* the list in an inconsistent state. It is essential to fix the problem.
* This method moves the object to the correct equivalence class, keeping the
* loopIterator where it was.
*
* @param arg0 The object to move.
* @return true if the object is a member of the set, false otherwise.
*/
public boolean resetEquivalenceClass(T arg0)
{
boolean found = false;
EqvPosition eqvPosition = new EqvPosition();
eqvPosition.matchingEqvClass = (List)m_itemToClassMap.get(arg0);
if (eqvPosition.matchingEqvClass != null)
{
removeAtPosition(eqvPosition, arg0);
found = true;
}
if (found)
{
addExpired(arg0);
}
return found;
}
}
If the given objects are equal
import java.lang.reflect.Array;
import java.util.Arrays;
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//Revised from springframework
/**
* Miscellaneous object utility methods. Mainly for internal use within the
* framework; consider Jakarta"s Commons Lang for a more comprehensive suite
* of object utilities.
*
* @author Juergen Hoeller
* @author Keith Donald
* @author Rod Johnson
* @author Rob Harrop
* @author Alex Ruiz
* @since 19.03.2004
* @see org.apache.rumons.lang.ObjectUtils
*/
abstract class ObjectUtils {
private static final int INITIAL_HASH = 7;
private static final int MULTIPLIER = 31;
private static final String EMPTY_STRING = "";
private static final String NULL_STRING = "null";
private static final String ARRAY_START = "{";
private static final String ARRAY_END = "}";
private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END;
private static final String ARRAY_ELEMENT_SEPARATOR = ", ";
/**
* Determine if the given objects are equal, returning <code>true</code>
* if both are <code>null</code> or <code>false</code> if only one is
* <code>null</code>.
* <p>Compares arrays with <code>Arrays.equals</code>, performing an equality
* check based on the array elements rather than the array reference.
* @param o1 first Object to compare
* @param o2 second Object to compare
* @return whether the given objects are equal
* @see java.util.Arrays#equals
*/
public static boolean nullSafeEquals(Object o1, Object o2) {
if (o1 == o2) {
return true;
}
if (o1 == null || o2 == null) {
return false;
}
if (o1.equals(o2)) {
return true;
}
if (o1 instanceof Object[] && o2 instanceof Object[]) {
return Arrays.equals((Object[]) o1, (Object[]) o2);
}
if (o1 instanceof boolean[] && o2 instanceof boolean[]) {
return Arrays.equals((boolean[]) o1, (boolean[]) o2);
}
if (o1 instanceof byte[] && o2 instanceof byte[]) {
return Arrays.equals((byte[]) o1, (byte[]) o2);
}
if (o1 instanceof char[] && o2 instanceof char[]) {
return Arrays.equals((char[]) o1, (char[]) o2);
}
if (o1 instanceof double[] && o2 instanceof double[]) {
return Arrays.equals((double[]) o1, (double[]) o2);
}
if (o1 instanceof float[] && o2 instanceof float[]) {
return Arrays.equals((float[]) o1, (float[]) o2);
}
if (o1 instanceof int[] && o2 instanceof int[]) {
return Arrays.equals((int[]) o1, (int[]) o2);
}
if (o1 instanceof long[] && o2 instanceof long[]) {
return Arrays.equals((long[]) o1, (long[]) o2);
}
if (o1 instanceof short[] && o2 instanceof short[]) {
return Arrays.equals((short[]) o1, (short[]) o2);
}
return false;
}
}
Test the equality of two object arrays
import java.lang.reflect.Array;
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
public class Main {
/**
* Test the equality of two object arrays.
*
* @param a The first array.
* @param b The second array.
* @param deep True to traverse elements which are arrays.
* @return True if arrays are equal.
*/
public static boolean equals(final Object[] a, final Object[] b,
final boolean deep)
{
if (a == b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (int i=0; i<a.length; i++) {
Object x = a[i];
Object y = b[i];
if (x != y) return false;
if (x == null || y == null) return false;
if (deep) {
if (x instanceof Object[] && y instanceof Object[]) {
if (! equals((Object[])x, (Object[])y, true)) return false;
}
else {
return false;
}
}
if (! x.equals(y)) return false;
}
return true;
}
/**
* Test the equality of two object arrays.
*
* @param a The first array.
* @param b The second array.
* @return True if arrays are equal.
*/
public static boolean equals(final Object[] a, final Object[] b) {
return equals(a, b, true);
}
}