Java tutorial
/* * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.print.attribute; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.HashMap; /** * Class {@code HashAttributeSet} provides an {@code AttributeSet} * implementation with characteristics of a hash map. * * @author Alan Kaminsky */ public class HashAttributeSet implements AttributeSet, Serializable { /** * Use serialVersionUID from JDK 1.4 for interoperability. */ private static final long serialVersionUID = 5311560590283707917L; /** * The interface of which all members of this attribute set must be an * instance. It is assumed to be interface {@link Attribute Attribute} or a * subinterface thereof. * * @serial */ private Class<?> myInterface; /** * A {@code HashMap} used by the implementation. The serialised form doesn't * include this instance variable. */ private transient HashMap<Class<?>, Attribute> attrMap = new HashMap<>(); /** * Write the instance to a stream (ie serialize the object). * * @param s the output stream * @throws IOException if an I/O exception has occurred * @serialData The serialized form of an attribute set explicitly writes the * number of attributes in the set, and each of the attributes. * This does not guarantee equality of serialized forms since * the order in which the attributes are written is not defined. */ private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); Attribute[] attrs = toArray(); s.writeInt(attrs.length); for (int i = 0; i < attrs.length; i++) { s.writeObject(attrs[i]); } } /** * Reconstitute an instance from a stream that is, deserialize it). * * @param s the input stream * @throws ClassNotFoundException if the class is not found * @throws IOException if an I/O exception has occurred */ private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { s.defaultReadObject(); attrMap = new HashMap<>(); int count = s.readInt(); Attribute attr; for (int i = 0; i < count; i++) { attr = (Attribute) s.readObject(); add(attr); } } /** * Construct a new, empty attribute set. */ public HashAttributeSet() { this(Attribute.class); } /** * Construct a new attribute set, initially populated with the given * attribute. * * @param attribute attribute value to add to the set * @throws NullPointerException if {@code attribute} is {@code null} */ public HashAttributeSet(Attribute attribute) { this(attribute, Attribute.class); } /** * Construct a new attribute set, initially populated with the values from * the given array. The new attribute set is populated by adding the * elements of {@code attributes} array to the set in sequence, starting at * index 0. Thus, later array elements may replace earlier array elements if * the array contains duplicate attribute values or attribute categories. * * @param attributes array of attribute values to add to the set. If * {@code null}, an empty attribute set is constructed. * @throws NullPointerException if any element of {@code attributes} is * {@code null} */ public HashAttributeSet(Attribute[] attributes) { this(attributes, Attribute.class); } /** * Construct a new attribute set, initially populated with the values from * the given set. * * @param attributes set of attributes from which to initialise this set. * If {@code null}, an empty attribute set is constructed. */ public HashAttributeSet(AttributeSet attributes) { this(attributes, Attribute.class); } /** * Construct a new, empty attribute set, where the members of the attribute * set are restricted to the given interface. * * @param interfaceName the interface of which all members of this * attribute set must be an instance. It is assumed to be interface * {@link Attribute Attribute} or a subinterface thereof. * @throws NullPointerException if {@code interfaceName} is {@code null} */ protected HashAttributeSet(Class<?> interfaceName) { if (interfaceName == null) { throw new NullPointerException("null interface"); } myInterface = interfaceName; } /** * Construct a new attribute set, initially populated with the given * attribute, where the members of the attribute set are restricted to the * given interface. * * @param attribute attribute value to add to the set * @param interfaceName the interface of which all members of this * attribute set must be an instance. It is assumed to be interface * {@link Attribute Attribute} or a subinterface thereof. * @throws NullPointerException if {@code attribute} or * {@code interfaceName} are {@code null} * @throws ClassCastException if {@code attribute} is not an instance of * {@code interfaceName} */ protected HashAttributeSet(Attribute attribute, Class<?> interfaceName) { if (interfaceName == null) { throw new NullPointerException("null interface"); } myInterface = interfaceName; add(attribute); } /** * Construct a new attribute set, where the members of the attribute set are * restricted to the given interface. The new attribute set is populated by * adding the elements of {@code attributes} array to the set in sequence, * starting at index 0. Thus, later array elements may replace earlier array * elements if the array contains duplicate attribute values or attribute * categories. * * @param attributes array of attribute values to add to the set. If * {@code null}, an empty attribute set is constructed. * @param interfaceName the interface of which all members of this * attribute set must be an instance. It is assumed to be interface * {@link Attribute Attribute} or a subinterface thereof. * @throws NullPointerException if {@code interfaceName} is {@code null}, or * if any element of {@code attributes} is {@code null} * @throws ClassCastException if any element of {@code attributes} is not an * instance of {@code interfaceName} */ protected HashAttributeSet(Attribute[] attributes, Class<?> interfaceName) { if (interfaceName == null) { throw new NullPointerException("null interface"); } myInterface = interfaceName; int n = attributes == null ? 0 : attributes.length; for (int i = 0; i < n; ++i) { add(attributes[i]); } } /** * Construct a new attribute set, initially populated with the values from * the given set where the members of the attribute set are restricted to * the given interface. * * @param attributes set of attribute values to initialise the set. If * {@code null}, an empty attribute set is constructed. * @param interfaceName The interface of which all members of this * attribute set must be an instance. It is assumed to be interface * {@link Attribute Attribute} or a subinterface thereof. * @throws ClassCastException if any element of {@code attributes} is not an * instance of {@code interfaceName} */ protected HashAttributeSet(AttributeSet attributes, Class<?> interfaceName) { myInterface = interfaceName; if (attributes != null) { Attribute[] attribArray = attributes.toArray(); int n = attribArray == null ? 0 : attribArray.length; for (int i = 0; i < n; ++i) { add(attribArray[i]); } } } /** * Returns the attribute value which this attribute set contains in the * given attribute category. Returns {@code null} if this attribute set does * not contain any attribute value in the given attribute category. * * @param category attribute category whose associated attribute value is * to be returned. It must be a {@link Class Class} that implements * interface {@link Attribute Attribute}. * @return the attribute value in the given attribute category contained in * this attribute set, or {@code null} if this attribute set does * not contain any attribute value in the given attribute category * @throws NullPointerException if the {@code category} is {@code null} * @throws ClassCastException if the {@code category} is not a * {@link Class Class} that implements interface * {@link Attribute Attribute} */ public Attribute get(Class<?> category) { return attrMap.get(AttributeSetUtilities.verifyAttributeCategory(category, Attribute.class)); } /** * Adds the specified attribute to this attribute set if it is not already * present, first removing any existing in the same attribute category as * the specified attribute value. * * @param attribute attribute value to be added to this attribute set * @return {@code true} if this attribute set changed as a result of the * call, i.e., the given attribute value was not already a member of * this attribute set * @throws NullPointerException if the {@code attribute} is {@code null} * @throws UnmodifiableSetException if this attribute set does not support * the {@code add()} operation */ public boolean add(Attribute attribute) { Object oldAttribute = attrMap.put(attribute.getCategory(), AttributeSetUtilities.verifyAttributeValue(attribute, myInterface)); return (!attribute.equals(oldAttribute)); } /** * Removes any attribute for this category from this attribute set if * present. If {@code category} is {@code null}, then {@code remove()} does * nothing and returns {@code false}. * * @param category attribute category to be removed from this attribute set * @return {@code true} if this attribute set changed as a result of the * call, i.e., the given attribute category had been a member of * this attribute set * @throws UnmodifiableSetException if this attribute set does not support * the {@code remove()} operation */ public boolean remove(Class<?> category) { return category != null && AttributeSetUtilities.verifyAttributeCategory(category, Attribute.class) != null && attrMap.remove(category) != null; } /** * Removes the specified attribute from this attribute set if present. If * {@code attribute} is {@code null}, then {@code remove()} does nothing and * returns {@code false}. * * @param attribute attribute value to be removed from this attribute set * @return {@code true} if this attribute set changed as a result of the * call, i.e., the given attribute value had been a member of this * attribute set * @throws UnmodifiableSetException if this attribute set does not support * the {@code remove()} operation */ public boolean remove(Attribute attribute) { return attribute != null && attrMap.remove(attribute.getCategory()) != null; } /** * Returns {@code true} if this attribute set contains an attribute for the * specified category. * * @param category whose presence in this attribute set is to be tested * @return {@code true} if this attribute set contains an attribute value * for the specified category */ public boolean containsKey(Class<?> category) { return category != null && AttributeSetUtilities.verifyAttributeCategory(category, Attribute.class) != null && attrMap.get(category) != null; } /** * Returns {@code true} if this attribute set contains the given attribute. * * @param attribute value whose presence in this attribute set is to be * tested * @return {@code true} if this attribute set contains the given attribute * value */ public boolean containsValue(Attribute attribute) { return attribute != null && attribute instanceof Attribute && attribute.equals(attrMap.get(attribute.getCategory())); } /** * Adds all of the elements in the specified set to this attribute. The * outcome is the same as if the {@link #add(Attribute) add(Attribute)} * operation had been applied to this attribute set successively with each * element from the specified set. The behavior of the * {@code addAll(AttributeSet)} operation is unspecified if the specified * set is modified while the operation is in progress. * <p> * If the {@code addAll(AttributeSet)} operation throws an exception, the * effect on this attribute set's state is implementation dependent; * elements from the specified set before the point of the exception may or * may not have been added to this attribute set. * * @param attributes whose elements are to be added to this attribute set * @return {@code true} if this attribute set changed as a result of the * call * @throws UnmodifiableSetException if this attribute set does not support * the {@code addAll(AttributeSet)} method * @throws NullPointerException if some element in the specified set is * {@code null}, or the set is {@code null} * @see #add(Attribute) */ public boolean addAll(AttributeSet attributes) { Attribute[] attrs = attributes.toArray(); boolean result = false; for (int i = 0; i < attrs.length; i++) { Attribute newValue = AttributeSetUtilities.verifyAttributeValue(attrs[i], myInterface); Object oldValue = attrMap.put(newValue.getCategory(), newValue); result = (!newValue.equals(oldValue)) || result; } return result; } /** * Returns the number of attributes in this attribute set. If this attribute * set contains more than {@code Integer.MAX_VALUE} elements, returns * {@code Integer.MAX_VALUE}. * * @return the number of attributes in this attribute set */ public int size() { return attrMap.size(); } /** * Returns an array of the attributes contained in this set. * * @return the attributes contained in this set as an array, zero length if * the {@code AttributeSet} is empty */ public Attribute[] toArray() { Attribute[] attrs = new Attribute[size()]; attrMap.values().toArray(attrs); return attrs; } /** * Removes all attributes from this attribute set. * * @throws UnmodifiableSetException if this attribute set does not support * the {@code clear()} operation */ public void clear() { attrMap.clear(); } /** * Returns {@code true} if this attribute set contains no attributes. * * @return {@code true} if this attribute set contains no attributes */ public boolean isEmpty() { return attrMap.isEmpty(); } /** * Compares the specified object with this attribute set for equality. * Returns {@code true} if the given object is also an attribute set and the * two attribute sets contain the same attribute category-attribute value * mappings. This ensures that the {@code equals()} method works properly * across different implementations of the {@code AttributeSet} interface. * * @param object to be compared for equality with this attribute set * @return {@code true} if the specified object is equal to this attribute * set */ public boolean equals(Object object) { if (object == null || !(object instanceof AttributeSet)) { return false; } AttributeSet aset = (AttributeSet) object; if (aset.size() != size()) { return false; } Attribute[] attrs = toArray(); for (int i = 0; i < attrs.length; i++) { if (!aset.containsValue(attrs[i])) { return false; } } return true; } /** * Returns the hash code value for this attribute set. The hash code of an * attribute set is defined to be the sum of the hash codes of each entry in * the {@code AttributeSet}. This ensures that {@code t1.equals(t2)} implies * that {@code t1.hashCode()==t2.hashCode()} for any two attribute sets * {@code t1} and {@code t2}, as required by the general contract of * {@link Object#hashCode() Object.hashCode()}. * * @return the hash code value for this attribute set */ public int hashCode() { int hcode = 0; Attribute[] attrs = toArray(); for (int i = 0; i < attrs.length; i++) { hcode += attrs[i].hashCode(); } return hcode; } }