0

Goal


I am making a Java class that will give enhanced usability to arrays, such as add, remove, and contains methods. I figured the best solution is to make a class (called ArrayPP) that has a type parameter T. This way, the user can interact with the ArrayPP object as easily as they can with an array of the same type.

Problem


I quickly found that such methods as add will require the creation of a separate array, and end up changing the target array t from an array of Ts into an array of Objects. As you may guess, this totally destroys the usability, and when I try to do something like

File[] f = new File[0];
ArrayPP<File> appF = new ArrayPP(f);
appF.add(saveFile);
f = appF.toArray();

the program throws

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.io.File;

because the add method has to change the array into an array of Objects, as the Java compiler won't let you make a generic array (T[] t = new T[0]; is bad, but T[] t = (T[]) new Object[0]; is okay). I know from line-by-line debugging that the above code keeps the array t, in this case, as a n array of Files UNTIL the 4th line of the add method is called. Does anyone have a solution that will keep the array t being an array of Ts and not an array of Objects?

Sample Code


Below is a VERY watered-down version of my class.

public class ArrayPP<T>
{
  T[] t;

  /**
   * Creates a new Array++ to manage the given array.
   * <h3>Analogy:</h3>
   * <tt>ArrayPP&lt;String&gt; s = new ArrayPP(args);</tt><br/>
   * is analogous to<br/>
   * <tt>String s[] = args;</tt>
   * @param array The array to be managed
   */
  public ArrayPP(T[] array)
  {
    t = array;
  }

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
    T[] temp = (T[]) new Object[t.length + 1];
    System.arraycopy(t, 0, temp, 0, t.length);
    temp[temp.length - 1] = val;
    t = (T[])temp;
    return this;
  }

  /**
   * Returns the array at the core of this wrapper
   * @return the array at the core of this wrapper
   */
  public T[] toArray()
  {
    return t;
  }
}

Possible Solution?


After looking at other questions about generic arrays, I think I have a solution:

Instead of

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
    T[] temp = (T[]) new Object[t.length + 1];
    System.arraycopy(t, 0, temp, 0, t.length);
    temp[temp.length - 1] = val;
    t = (T[])temp;
    return this;
  }

will this work?

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP<T> add(T val)
  {
    t = java.util.Arrays.copyOf(t, t.length + 1);
    t[t.length - 1] = val;
    return this;
  }
4
  • 3
    Umm, that class already exists ... it's called java.util.ArrayList. Commented Mar 20, 2011 at 23:04
  • ArrayList doesn't have all the capabilities I'm looking for Commented Mar 20, 2011 at 23:27
  • what capabilities doesn't ArrayList have that you need? Can't you just create a class that extends ArrayList? Commented Mar 21, 2011 at 3:15
  • If you want, my code will be available in open source. Send an email to me at [email protected] if you want me to explain, in-depth, why I must make an entirely new class. Commented Mar 29, 2011 at 3:12

3 Answers 3

2

In principle you can't easily create arrays of a generic type (or type variable).

If you have a class object, you can use reflection, or if you have an example array, the methods in the java.util.Arrays class to create a (longer/shorter) copy. But it is not elegant either way.

The ArrayList class internally simply uses an Object[] to store its elements, and converts only on get/set/add/toArray. What would your class do better than ArrayList?


Edit:

I would recommend either simply delegate to an ArraysList, or do the implementation like ArrayList does, using an Object[] internally, and converting on output where necessary.

If you really want to have an array of the right type internally, it is possible - but it gets ugly, as I said.

The add method is still the easiest case:

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
     T[] temp = Arrays.copyOf(t, t.length+1);
     temp[t.length] = val;
     t = temp;
     return this;
  }

When you want to add in the middle or remove, you'll have to combine this with your arraycopy.

Sign up to request clarification or add additional context in comments.

1 Comment

it implements such interfaces as Comparable and has methods that complexly and intelligently remove different types of objects. Again, what I show is only what needs to be seen for this question.
1

Is there some reason the built-it List<T> class(es) can't do what you need? As in:

String[] theArray = {"a", "b", "c"};
List<String> theList = Arrays.asList(theArray);

4 Comments

Yes, there is. This class has methods that are implemented from interfaces such as Comparable, but they aren't shown here. My problem is with methods that change the array's size such as add, remove, insert, etc.
Sorry if this is a stupid question, but then couldn't you extend ArrayList (for instance), and add your additional methods there (or override the existing ones that you want to change)?
I suppose I could, but I don't want to. You see, my aim is not to REPLACE any classes, but to make my own. For instance, I don't want my class to have an asList method, because I want it to be entirely arrays.
(There's a name for this: its called "NIH Syndrome". If left untreated it can develop into full blown "Custom Framework" disease.)
0
public ArrayPP(T[] array)
    componentClass = array.getClass().getComponentClass();

T[] newArray(int length)
    return Array.newInstance(componentClass, length)

2 Comments

my problem is with the add method
T[] temp = newArray( t.length + 1 )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.