001/* ======================================================================== 002 * JCommon : a free general purpose class library for the Java(tm) platform 003 * ======================================================================== 004 * 005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jcommon/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ----------------------- 028 * AbstractObjectList.java 029 * ----------------------- 030 * (C)opyright 2003, 2004, by Object Refinery Limited and Contributors. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): Bill Kelemen; 034 * Nicolas Brodu 035 * 036 * $Id: AbstractObjectList.java,v 1.5 2005/10/18 13:24:19 mungady Exp $ 037 * 038 * Changes 039 * ------- 040 * 13-Aug-2003 : Version 1, based on ObjectList (DG); 041 * 24-Aug-2003 : Fixed size (BK); 042 * 15-Sep-2003 : Fix serialization for subclasses (ShapeList, PaintList) (NB); 043 */ 044 045package org.jfree.util; 046 047import java.io.IOException; 048import java.io.ObjectInputStream; 049import java.io.ObjectOutputStream; 050import java.io.Serializable; 051import java.util.Arrays; 052 053/** 054 * A list of objects that can grow as required. 055 * 056 * @author David Gilbert 057 */ 058public class AbstractObjectList implements Cloneable, Serializable { 059 060 /** For serialization. */ 061 private static final long serialVersionUID = 7789833772597351595L; 062 063 /** The default initial capacity of the list. */ 064 public static final int DEFAULT_INITIAL_CAPACITY = 8; 065 066 /** Storage for the objects. */ 067 private transient Object[] objects; 068 069 /** The current list size. */ 070 private int size = 0; 071 072 /** The default increment. */ 073 private int increment = DEFAULT_INITIAL_CAPACITY; 074 075 /** 076 * Creates a new list with the default initial capacity. 077 */ 078 protected AbstractObjectList() { 079 this(DEFAULT_INITIAL_CAPACITY); 080 } 081 082 /** 083 * Creates a new list. 084 * 085 * @param initialCapacity the initial capacity. 086 */ 087 protected AbstractObjectList(final int initialCapacity) { 088 this (initialCapacity, initialCapacity); 089 } 090 091 /** 092 * Creates a new list. 093 * 094 * @param initialCapacity the initial capacity. 095 * @param increment the increment. 096 */ 097 protected AbstractObjectList(final int initialCapacity, 098 final int increment) { 099 this.objects = new Object[initialCapacity]; 100 this.increment = increment; 101 } 102 103 /** 104 * Returns the object at the specified index, if there is one, or 105 * <code>null</code>. 106 * 107 * @param index the object index. 108 * 109 * @return The object or <code>null</code>. 110 */ 111 protected Object get(final int index) { 112 Object result = null; 113 if (index >= 0 && index < this.size) { 114 result = this.objects[index]; 115 } 116 return result; 117 } 118 119 /** 120 * Sets an object reference (overwriting any existing object). 121 * 122 * @param index the object index. 123 * @param object the object (<code>null</code> permitted). 124 */ 125 protected void set(final int index, final Object object) { 126 if (index < 0) { 127 throw new IllegalArgumentException("Requires index >= 0."); 128 } 129 if (index >= this.objects.length) { 130 final Object[] enlarged = new Object[index + this.increment]; 131 System.arraycopy(this.objects, 0, enlarged, 0, this.objects.length); 132 this.objects = enlarged; 133 } 134 this.objects[index] = object; 135 this.size = Math.max(this.size, index + 1); 136 } 137 138 /** 139 * Clears the list. 140 */ 141 public void clear() { 142 Arrays.fill(this.objects, null); 143 this.size = 0; 144 } 145 146 /** 147 * Returns the size of the list. 148 * 149 * @return The size of the list. 150 */ 151 public int size() { 152 return this.size; 153 } 154 155 /** 156 * Returns the index of the specified object, or -1 if the object is not in 157 * the list. 158 * 159 * @param object the object. 160 * 161 * @return The index or -1. 162 */ 163 protected int indexOf(final Object object) { 164 for (int index = 0; index < this.size; index++) { 165 if (this.objects[index] == object) { 166 return (index); 167 } 168 } 169 return -1; 170 } 171 172 /** 173 * Tests this list for equality with another object. 174 * 175 * @param obj the object to test. 176 * 177 * @return A boolean. 178 */ 179 public boolean equals(final Object obj) { 180 181 if (obj == null) { 182 return false; 183 } 184 185 if (obj == this) { 186 return true; 187 } 188 189 if (!(obj instanceof AbstractObjectList)) { 190 return false; 191 } 192 193 final AbstractObjectList other = (AbstractObjectList) obj; 194 final int listSize = size(); 195 for (int i = 0; i < listSize; i++) { 196 if (!ObjectUtilities.equal(get(i), other.get(i))) { 197 return false; 198 } 199 } 200 return true; 201 } 202 203 /** 204 * Returns a hash code value for the object. 205 * 206 * @return the hashcode 207 */ 208 public int hashCode() { 209 return super.hashCode(); 210 } 211 212 /** 213 * Clones the list of objects. The objects in the list are not cloned, so 214 * this is method makes a 'shallow' copy of the list. 215 * 216 * @return A clone. 217 * 218 * @throws CloneNotSupportedException if an item in the list does not 219 * support cloning. 220 */ 221 public Object clone() throws CloneNotSupportedException { 222 223 final AbstractObjectList clone = (AbstractObjectList) super.clone(); 224 if (this.objects != null) { 225 clone.objects = new Object[this.objects.length]; 226 System.arraycopy( 227 this.objects, 0, clone.objects, 0, this.objects.length 228 ); 229 } 230 return clone; 231 232 } 233 234 /** 235 * Provides serialization support. 236 * 237 * @param stream the output stream. 238 * 239 * @throws IOException if there is an I/O error. 240 */ 241 private void writeObject(final ObjectOutputStream stream) 242 throws IOException { 243 244 stream.defaultWriteObject(); 245 final int count = size(); 246 stream.writeInt(count); 247 for (int i = 0; i < count; i++) { 248 final Object object = get(i); 249 if (object != null && object instanceof Serializable) { 250 stream.writeInt(i); 251 stream.writeObject(object); 252 } 253 else { 254 stream.writeInt(-1); 255 } 256 } 257 258 } 259 260 /** 261 * Provides serialization support. 262 * 263 * @param stream the input stream. 264 * 265 * @throws IOException if there is an I/O error. 266 * @throws ClassNotFoundException if there is a classpath problem. 267 */ 268 private void readObject(final ObjectInputStream stream) 269 throws IOException, ClassNotFoundException { 270 271 stream.defaultReadObject(); 272 this.objects = new Object[this.size]; 273 final int count = stream.readInt(); 274 for (int i = 0; i < count; i++) { 275 final int index = stream.readInt(); 276 if (index != -1) { 277 set(index, stream.readObject()); 278 } 279 } 280 281 } 282 283}