3

Why can't I make two overloaded methods whose parameters are both array lists, but with different data types?

public class test {
  public static void main(String[] args){

    ArrayList<Integer> ints = new ArrayList<Integer>();
    ints.add(1);
    ints.add(2);
    ints.add(3);
    ints.add(4);
    ints.add(5);

    showFirst(ints);

    ArrayList<Double> dubs = new ArrayList<Double>();
    dubs.add(1.1);
    dubs.add(2.2);
    dubs.add(3.3);
    dubs.add(4.4);
    dubs.add(5.5);

    showFirst(dubs);
  } 

  public static void showFirst(ArrayList<Integer> a)
  {
    System.out.println(a.remove(0));
  }

  public static void showFirst(ArrayList<Double> a)
  {
    System.out.println(a.remove(0));
  }
}

I am in eclipse, and it underlines the problem causing code in red and gives this message: Method showFirst(ArrayList<Integer>) has the same erasure showFirst(ArrayList<E>) as another method in type test

The only way I could get it to work is my adding other parameters, such as , int b after showFirst(ArrayList<Integer> a and , int b after showFirst(ArrayList<Double> a.

Is there any way to make this code work the way I intended? If not, I'd like to know why this is happening.

Running the program generates the following error message:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
  The method showFirst(ArrayList<Integer>) in the type test is not applicable for the arguments (ArrayList<Double>)
at test.test.main(test.java:25)

Edit:

Using or , what if I wanted to do things where I need the data type such as:

public static int[] reverseInArray(ArrayList<Integer> a)
  {
    int n = a.size();
    int[] b = new int[n];
    while(n > 0)
    {
    b[n] = a.remove(0);
    n--;
    }
    return b;
  }

  public static double[] reverseInArray(ArrayList<Double> a)
  {
    double n = a.size();
    double[] b = new int[n];
    while(I > 0)
    {
    b[n] = a.remove(0);
    n--;
    }
    return b;
  }
Max
  • 12,622
  • 16
  • 73
  • 101

5 Answers5

12

At run time, every ArrayList<Whatever> will be converted to ArrayList (raw) due to type erasure. So, just have one method that receives List<? extends Number>.

//renamed to show what the method really does
public static void removeFirst(List<? extends Number> a) {
    System.out.println(a.remove(0));
}

Note that the method above will work only for Lists (ArrayList, LinkedList and other implementations of List) which declares to hold a class that extends from Number. If you want/need a method to remove the first element from List that holds any type, use List<?> instead:

public static void removeFirst(List<?> a) {
    System.out.println(a.remove(0));
}

Remember to always program to interfaces instead of specific class implementation.

Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
3

Generics are only enforced at compile time. At runtime an ArrayList is an ArrayList.

You can combine the two methods in this particular case, though:

public static void showFirst(ArrayList<? extends Number> a)
{
    System.out.println(a.remove(0));
}
Mike B
  • 5,390
  • 2
  • 23
  • 45
3

Because generics are erased at runtime. In other words, your code doesn't know that the two methods are different. In fact, you have another compiler error that you're not telling us about:

Method showFirst(ArrayList<Integer>) has the same erasure showFirst(ArrayList<E>) as another method in type Main
Kevin Workman
  • 41,537
  • 9
  • 68
  • 107
3

... because of type erasure, your generic parameters are unknown at runtime, hence your overridden methods share an ambiguous signature.

Mena
  • 47,782
  • 11
  • 87
  • 106
2

Have this method only, because, generics are available only in compile, so, both of your methods are compiled to same signature. So it's ambiguous which method to be called

public static void showFirst(ArrayList<? extends Number> a)
{
    System.out.println(a.remove(0));
}
Abimaran Kugathasan
  • 31,165
  • 11
  • 75
  • 105