Returning an array of generic type

Join the discussion
Ask a follow-up here, or get your own question answered by working scientists, mathematicians and engineers — people, not an autocomplete.
Real named experts · corrections over time · the nuance an AI answer skips
1 reply · 2K views
Enharmonics
Messages
29
Reaction score
2
Moved thread to homework forum
This is a homework problem, so I have to follow some stipulations, namely:

Do not change the method header in any way.
Do not use the classes Arrays, Collections, Set, or Map.
You can use the java.lang.reflect.Array class. Use equals to
test if two items are equal.

The method

Java:
public static <T>
T[] commonItems( T[] arr1, T[] arr2)

returns an array that contains the items that occur in both array1 and array2. Assume that the 2 arrays have no duplicate items. If one or both arrays are null, the output is the null array. If the 2 arrays have no atoms in common, commonItems returns the empty array.

The problem is, I have no idea how to get a method to return a generic-type array. Because of type erasure, I can't create an instance T[] of a generic array, empty or otherwise.

The only way I was able to do it was by setting the generic array reference variable to null. My first plan was to do that, then use an ArrayList of generic type to store the elements arr1 and arr2 have in common, and finally use the toArray() method to convert it into a "generic-type" array, which would be stored in the null-valued T[] reference variable, something like this:

Code:
public static <T>
T[] commonItems( T[] arr1, T[] arr2)
{
      ArrayList<T> commonElements = new ArrayList<>();
      T[] commonItems = null;

      // Code for finding the common elements goes here

     return commonElements.toArray(commonItems);
}

The above code results in a NullPointerException being thrown (presumably because commonItems was initialized to null and not an array of any kind)

Next I tried circumventing the "no generic array instantiation" rule by creating an array of type Object[] and casting it into a "generic type" array:

Code:
      ArrayList<T> commonElements = new ArrayList<>();
      T[] commonItems = (T[]) new Object[]{};

      // Code for finding the common elements goes here

     return commonElements.toArray(commonItems);

Which results in a ClassCastException.

I googled around and checked on Stack Overflow for a while about how to return generic-type arrays, and tried my own implementation of the closest thing I could find to a workaround, which basically involves writing a "conversion" method and using Array.newInstance() to make the generic array to be returned:

Java:
public static <T>
    T[] commonItems(T[] arr1, T[] arr2)
    {
       
        // commonElements will store the elements
        // that occur in both arr1 and arr2
  
        ArrayList<T> commonElements = new ArrayList<>();
        T[] commonItems = null;
       
        // If one or both arr1 and arr2
        // are null, the output is the
        // null array
       
        if (arr1 == null || arr2 == null)
        {
            return commonItems;
        }
       
        // Nested enhanced for loops
        // used to iterate through the
        // two arrays
       
        for (T firstElement : arr1)
        {
            for (T secondElement : arr2)
            {
                // If the two elements are
                // equal, add it to
                // commonElements
               
                if (firstElement.equals(secondElement))
                    commonElements.add(firstElement);
            }
        }
       
        // Return an array containing the
        // common items in arr1 and arr2
       
        return convertToArray(commonElements, arr1.getClass());
    }
   
    // HELPER METHOD FOR commonItems METHOD
   
    public static <T>
    T[] convertToArray(ArrayList<T> commonElements, Class<? extends Object[]> c)
    {
        // Use the newInstance() method to
        // instantiate an array, then cast
        // it to a generic type.
       
        T[] commonItems = (T[]) Array.newInstance(c, commonElements.size());
       
        // Now use the toArray() method
        // to convert commonElements
        // into an array of "generic"
        // type
       
        commonItems = commonElements.toArray(commonItems);
       
        // Return the array
       
        return (T[]) commonItems;
    }

Which results in an ArrayStoreException at the line

Code:
commonItems = commonElements.toArray(commonItems);

I know that generic arrays (like T[]) would be converted to Object[] type arrays at runtime due to type erasure, but because of the method header (which I'm not allowed to change) the method won't run unless I return an array of type T[].

I'm guessing the idea behind the method is for the "generic array" to be of the same type as arr1 and arr2, which was my reasoning for passing arr1.getClass() to the convertToArray method and trying to use it as an argument for the newInstance() method.

But I don't know what else to try at this point.
 
Physics news on Phys.org
You created an array of arrays because your variable c was the class of T[] instead of the class of T.
Anyway I think I got it to work. Try this.
Java:
T[] commonItems(T[] arr1, T[] arr2)
{
    ArrayList<T> commonElements = new ArrayList<>();
    T[] commonItems = null;

    if (arr1 == null || arr2 == null)
    {
        return commonItems;
    }

    for (T firstElement : arr1)
    {
        for (T secondElement : arr2)
        {
            if (firstElement.equals(secondElement))
                commonElements.add(firstElement);
        }
    }

    if(commonElements.size() > 0) {
      commonItems = (T[]) Array.newInstance(commonElements.get(0).getClass(), commonElements.size());
      commonElements.toArray(commonItems);
    } else if(arr1.length > 0) {
      commonItems = (T[]) Array.newInstance(arr1[0].getClass(), 0);
    } else if(arr2.length > 0) {
      commonItems = (T[]) Array.newInstance(arr2[0].getClass(), 0);
    } else {
      commonItems = (T[])arr1.clone();
    }
    return commonItems;
}
 
Last edited: