/* * @(#) ConstVector.java - Class for immutable vectors for objects. * (c) 2000 Ivan Maidanski http://ivmai.chat.ru * Freeware class library sources. All rights reserved. ** * Language: Java [pure] * Tested with: JDK v1.1.6 * Last modified: 2000-12-31 17:50:00 GMT+03:00 */ /* * This software is the proprietary information of the author. ** * Permission to use, copy, and distribute this software and its * documentation for non-commercial purposes and without fee is * hereby granted provided that this copyright notice appears in all * copies. ** * This software should not be modified in any way; any found bug * should be reported to the author. ** * The author disclaims all warranties with regard to this software, * including all implied warranties of merchantability and fitness. * In no event shall the author be liable for any special, indirect * or consequential damages or any damages whatsoever resulting from * loss of use, data or profits, whether in an action of contract, * negligence or other tortuous action, arising out of or in * connection with the use or performance of this software. */ package ivmai.util; import java.io.InvalidObjectException; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; /** * Class for immutable vectors for objects. ** * This final class is useful for representation of a * constant vector (container) of custom objects of any type. An * instance of this class encapsulates/wraps (when constructed) a * given Object array. Important notes: the component * type of the encapsulated Object array is hidden; an * object of this class may be serialized only if all custom objects * it contains are serializable. ** * @see ConstPair * @see ObjectVector * @see GComparator ** * @version 2.0 * @author Ivan Maidanski ** * @since 1.2 */ public final class ConstVector implements Immutable, ReallyCloneable, Serializable, Indexable, Sortable, Verifiable { /** * The class version unique identifier for serialization * interoperability. ** * @since 1.8 */ private static final long serialVersionUID = 3843350134190606883L; /** * The wrapped (encapsulated) custom array of objects. ** * array must be non-null (but its elements * may be null). Important notes: * array[index] must not be changed anyhow for every * index; the component type of array is of no * use here. ** * @serial ** * @see ConstVector#ConstVector(java.lang.Object[]) * @see #length() * @see #getAt(int) * @see #toArray() * @see #integrityCheck() */ protected final Object[] array; /** * Constructs an immutable vector by wrapping a given custom array * of objects. ** * Important notes: array[index] must not be changed * anyhow for each index (since no cloning is performed for * array here). ** * @param array * the object array (must be non-null) to be * encapsulated. * @exception NullPointerException * if array is null. ** * @see #getAt(int) * @see #toArray() * @see #equals(java.lang.Object) * @see #greaterThan(java.lang.Object) * @see #toString() */ public ConstVector(Object[] array) throws NullPointerException { int len; len = array.length; this.array = array; } /** * Returns the number of elements in this vector. ** * The result is the same as length of * toArray(). ** * @return * amount (non-negative value) of elements. ** * @see #getAt(int) * @see #toArray() */ public int length() { return this.array.length; } /** * Returns value of the element at the specified index. ** * The result is the same as of toArray()[index]. ** * @param index * the index (must be in the range) at which to return an element. * @return * an element (may be null) at index. * @exception ArrayIndexOutOfBoundsException * if index is negative or is not less than * length(). ** * @see ConstVector#ConstVector(java.lang.Object[]) * @see #length() * @see #toArray() */ public Object getAt(int index) throws ArrayIndexOutOfBoundsException { return this.array[index]; } /** * Returns a newly created array filled with the values of the * elements of this vector. ** * Here, the result is the exact instance of Object[]. ** * @return * a new array (not null), containing values of all the * elements of this vector. * @exception OutOfMemoryError * if there is not enough memory. ** * @see ConstVector#ConstVector(java.lang.Object[]) * @see #getAt(int) * @see #length() * @see #equals(java.lang.Object) * @see #greaterThan(java.lang.Object) * @see #toString() */ public Object[] toArray() { Object[] array, newArray; int len = (array = this.array).length; System.arraycopy(array, 0, newArray = new Object[len], 0, len); return newArray; } /** * Creates and returns a copy of this object. ** * Important notes: the encapsulated array is not cloned itself. ** * @return * a copy (not null and != this) of * this instance. * @exception OutOfMemoryError * if there is not enough memory. ** * @see ConstVector#ConstVector(java.lang.Object[]) * @see #toArray() * @see #equals(java.lang.Object) */ public Object clone() { Object obj; try { if ((obj = super.clone()) instanceof ConstVector && obj != this) return obj; } catch (CloneNotSupportedException e) {} throw new InternalError("CloneNotSupportedException"); } /** * Computes and returns a hash code value for the object. ** * This method hashes all non-null elements of * this vector and mixes them all to produce a single * hash code value. ** * @return * a hash code value for this object. ** * @see #length() * @see #getAt(int) * @see #equals(java.lang.Object) */ public int hashCode() { Object[] array = this.array; int code = 0, offset = 0; Object value; for (int len = array.length; offset < len; code = (code << 5) - code) if ((value = array[offset++]) != null) code ^= value.hashCode(); return code ^ offset; } /** * Indicates whether this object is equal to the * specified one. ** * This method returns true if and only if * obj is instance of this vector class and all the * elements of this vector are equal to the * corresponding elements of obj vector. ** * @param obj * the object (may be null) with which to compare. * @return * true if and only if this value is the * same as obj value. ** * @see #length() * @see #getAt(int) * @see #hashCode() * @see #greaterThan(java.lang.Object) */ public boolean equals(Object obj) { if (obj != this) { if (!(obj instanceof ConstVector)) return false; int offset; Object[] otherArray = ((ConstVector)obj).array, array; if ((array = this.array) != otherArray) { if ((offset = array.length) != otherArray.length) return false; Object value; while (offset-- > 0) if ((value = array[offset]) != null) { if (!value.equals(otherArray[offset])) return false; } else if (otherArray[offset] != null) return false; } } return true; } /** * Tests for being semantically greater than the argument. ** * The result is true if and only if obj is * instance of this class and this object * is greater than the specified object. Vectors are compared in the * element-by-element manner, starting at index 0 and * at each index elements are compared for equality and the first * non-equal elements pair is compared through INSTANCE * of GComparator class. ** * @param obj * the second compared object (may be null). * @return * true if obj is comparable with * this and this object is greater than * obj, else false. ** * @see #length() * @see #getAt(int) * @see #equals(java.lang.Object) ** * @since 1.8 */ public boolean greaterThan(Object obj) { int offset; Object[] array = this.array, otherArray; boolean isGreater = false; if (obj != this && obj instanceof ConstVector && (otherArray = ((ConstVector)obj).array) != array) { int len = array.length; if ((offset = otherArray.length) < len) { isGreater = true; len = offset; } for (offset = 0; offset < len; offset++) { Object value, temp = otherArray[offset]; if ((value = array[offset]) != null && !value.equals(temp) || value == null && temp != null) { isGreater = GComparator.INSTANCE.greater(value, temp); break; } } } return isGreater; } /** * Converts vector to its 'in-line' string representation. ** * The string representations of the values (if value is * null then "null") of this vector are * placed into the resulting string in the direct index order, * delimited by a single space. ** * @return * the string representation (not null) of * this object. * @exception OutOfMemoryError * if there is not enough memory. ** * @see ConstVector#ConstVector(java.lang.Object[]) * @see #toArray() */ public String toString() { Object[] array = this.array; int offset = 0, len = array.length; StringBuffer sBuf = new StringBuffer((len << 2) > 24 ? len << 2 : 24); if (len > 0) do { Object value; sBuf.append((value = array[offset]) != null ? value.toString() : "null"); if (++offset >= len) break; sBuf.append(' '); } while (true); return new String(sBuf); } /** * Verifies this object for its integrity. ** * The elements are not checked. For debug purpose only. ** * @exception InternalError * if integrity violation is detected. ** * @see ConstVector#ConstVector(java.lang.Object[]) ** * @since 2.0 */ public void integrityCheck() { if (this.array == null) throw new InternalError("array: null"); } /** * Deserializes an object of this class from a given stream. ** * This method is responsible for reading from in stream, * restoring the classes fields, and verifying that the serialized * object is not corrupted. First of all, it calls * defaultReadObject() for in to invoke the * default deserialization mechanism. Then, it restores the state of * transient fields and performs additional * verification of the deserialized object. This method is used only * internally by ObjectInputStream class. ** * @param in * the stream (must be non-null) to read data from in * order to restore the object. * @exception NullPointerException * if in is null. * @exception IOException * if any I/O error occurs or the serialized object is corrupted. * @exception ClassNotFoundException * if the class for an object being restored cannot be found. * @exception OutOfMemoryError * if there is not enough memory. ** * @see ConstVector#ConstVector(java.lang.Object[]) * @see #integrityCheck() */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); if (this.array == null) throw new InvalidObjectException("array: null"); } }