The Java method signature you gave is for a generic method (i.e. one that binds a type variable). This allows you to specify that your list must have that element type, allowing you to both retrieve and insert elements into the list safely, knowing they're of that type. You can do this in Kotlin too:
public <T extends Person> void bar(List<T> list);
is equivalent to
fun <T: Person> bar(list: MutableList<T>)
However, the Kotlin method signature you gave in your question is not generic, but has a wildcard generic argument. You can do this in Java too:
fun bar(list: MutableList<in Person>)
is equivalent to
public void bar(List<? super Person> list);
This is different to the generic method signature above. In the generic method, we can create variables of type T
by taking elements out of the list, and we know that these are a subtype of Person
. Since list
has been bound to have element type T
we also know that we can insert such variables back into the list.
With the non-generic, wildcard signature, we can't do that. In both the Java and Kotlin cases we have a method that takes any list whose element type is a supertype of Person
. So, when we get elements out of the list, all we know for certain is that they are a supertype of Person
, and the only type that fits this condition is Object
/Any
. However, the constraint on the wildcard does tell us that it should be fine to insert elements of type Person
(or a subtype) into the list.
Just for completeness, the converse is also possible:
public void bar(List<? extends Person> list);
is equivalent to
fun bar(list: MutableList<out Person>)
Here, the method can take any list whose element type is a subtype of Person
. We know that if we extract an element from the list, it will conform to the Person
interface, so we can assign it to a variable of type Person
. However, we don't know anything about what types we can insert into the list, as we don't know the exact subtype of Person
the list accepts. Even though we know that a value we've just extracted from the list must be an acceptable type for insertion, I believe neither Kotlin nor Java is clever enough to infer this. You have to use the generic method signature as a "hint".