10

I have a method which takes a List<?> as an argument.

public static String method(List<?> arg){
     // Do something based on type of the list
}

//I call the method as below
List<ClassA> listA = new ArrayList<ClassA>();
List<ClassB> listB = new ArrayList<ClassB>();
method(listA);
method(listB);

In method, how do I know if arg is a List of ClassA or a List of ClassB?

jahroy
  • 22,322
  • 9
  • 59
  • 108
user682765
  • 1,229
  • 3
  • 21
  • 33
  • 2
    Declaring the parameter type as `>` means exactly that you're not interested in the actual type. – biziclop Apr 13 '12 at 22:33
  • I used if(arg.get(0) instanceof ClassA) // do something .... And I am getting intended results. Bt not sure if that would be the right way to do so, from the replies here. – user682765 Apr 13 '12 at 22:56
  • 1
    You could do that even if you weren't using generics (just remove the > to demonstrate this). The point of generics is to make it so you don't have to use instanceof or worry about unsafe casting. – jahroy Apr 13 '12 at 22:57

2 Answers2

28

Technically speaking, you CAN use instanceof to check if an object is a certain type.

However... That's NOT a good idea.

The way you've declared your method, it can accept a List of any type, so it isn't necessarily going to be A or B.

It's hard to tell what you're trying to do, but you probably should make your method generic.

You can do so like this:

public static <T> String method(List<T> arg) {
    // We now know that the type of the list is T, which is
    // determined based on the type of list passed to this
    // method.  This would demonstrate the point better if
    // the return type was T, but I'm leaving the return type
    // as String, because that's what your code returns.
}

Here's a better example:

If you want to create a generic method that returns the first element of a list, you would do it like this:

public static <T> T firstElement(List<T> theList) {
    if (theList == null) {
        return null;
    }
    T objectOfTypeT = theList.get(0);
    return objectOfTypeT;
}

Note that the return type is now T.

Because we made this method generic, it can return the same type that is used in the List.

You would typically just return theList.get(0), but I added a line to make the purpose of generics more obvious.

Explanation of syntax:

  • The <T> indicates that this method takes one type parameter named T.

  • The T that immediately follows is the return type (just like you would normally return String, Integer, etc...).

  • The T in the List parameter is how the compiler knows what the heck a T is.

This allows the compiler to say: "This method expects something of type T. Oh look... The list is also of type T. If somebody passes a list of Strings to this method, than T must be a String. If somebody passes a list of Integers to this method, T must be an Integer."

In contrast, your method can only return a String and it has no idea what type is used in the List.


Also...

If A and B both extend the same class, named TheParentClass, you could declare your method like this:

public static String method(List<? extends TheParentClass> arg)

That way, you'd know a little more about the possible types of your parameter (and can benefit from compile time type checking).

jahroy
  • 22,322
  • 9
  • 59
  • 108
  • 1
    That last example you gave of "? extends TheParentClass" is probably how the ? was "meant" to be used. Allowing the use of a ? without the extends bit is, like David Mason suggests, bad practice but legal. I think jahroy should be awarded the answer to this question rather than me because he nailed it. – djangofan Mar 19 '13 at 20:10
4

From an answer by the user called Romain " If you use < ?>, you mean you aren't going to use the parametrized type anywhere. Either go to the specific type (in your case it seems List< String>) or to the very generic List< Object> "

Also, I believe that if you use the question mark the compiler wont catch type mismatches until runtime (reified; p.119 of Effective Java), bypassing erasure, and effectively elimating the benefit you get from using generic types???

TO answer the question of the questioner: if you use List< Object> and then try to cast it to A or to B , possibly using instanceOf , that might be a way to tell what it is. I bet there is a better way to do it than that though.

Community
  • 1
  • 1
djangofan
  • 28,471
  • 61
  • 196
  • 289
  • 1
    +1 for the OP is _effectively eliminating the benefit you get from using generic types_ – jahroy Apr 13 '12 at 23:11
  • 2
    > means "I'm not using generics but I want to get rid of the compiler warning." – user949300 Feb 07 '13 at 23:31
  • 6
    -1 because this answer encourages bad coding practice. Defining a method that takes a generic type argument is the appropriate way to do this - it gives you type safety and does not require messy casting. See answer by jahroy. – David Mason Mar 19 '13 at 03:19