Нет, foo(? obj)
на самом деле не то же самое, что foo(Object obj)
. Разница в том, что когда тип параметра Object
, он явно заявляет, что любой тип объекта является допустимым. С типом параметра ?
метод утверждает, что не знает , какой тип объекта является допустимым ... поэтому ничего не допустимо, кроме null
.
Причина этого становится очевидной, когда вы рассматриваете List
, а не произвольный интерфейс. Посмотрите на этот метод:
public void foo(List<?> list) {
list.add(...); // what can we add here?
}
?
указывает, что любой тип List
является приемлемым ... переданный List
может быть List<String>
, List<Integer>
или List<Map<Foo, Bar>>
. Там нет никакого способа узнать. Обратите внимание, что это проблема только методов, которые используют универсальных параметров, таких как add
или ваш метод foo
. Для методов, которые производят (возвращают) объект универсального типа, можно использовать такой метод и назначить результат как Object
. Это, в отличие от метода потребителя, не может повредить внутреннее состояние универсального объекта.
Также обратите внимание, что когда вы звоните ((A<?>) new B()).foo(new Object())
, вы пытаетесь сделать что-то незаконное ... если что-то (например, Object
), которое не является B
, должно быть передано B
' s foo
метод, он взорвется во время выполнения. Компилятор правильно запрещает вам делать это.
Возможно, вы также захотите проверить мой ответ на другой вопрос здесь , который объясняет некоторые вещи об ограниченных типах подстановочных знаков и тому подобном.