Ну, вы можете адаптировать некоторые примеры из той же главы, чтобы воспроизвести случай этого.
Например, рассмотрим следующий обобщенный класс:
class Node<E> {
private E value;
@Override public String toString(){ return value.toString(); }
}
Теперь представьте себечто вы пишете следующий фрагмент кода, что неверно:
Object o = new Node<Integer>(10);
Node<String> node = new Node<>("Hello");
if(o instanceof Node) {
Node other = (Node) o;
other.value = node.value; //Uh oh! Warning
}
System.out.println(node); //Hello
System.out.println(other); //Hello - WTH!
Если вы попытаетесь скомпилировать это, вы получите только предупреждение, но оно все равно будет прекрасно скомпилировано:
javac -Xlint:unchecked Node.java
Node.java:21: warning: [unchecked] unchecked assignment to variable value as member of raw type Node
other.value = node.value;
^
1 warning
Однако, если вы измените код для использования неограниченных подстановочных знаков:
Object o = new Node<Integer>(10);
Node<String> node = new Node<>("Hello");
if(o instanceof Node<?>) {
Node<?> other = (Node<?>) o;
other.value = node.value; //Uh oh! Compiler error
}
Теперь вы получите следующую ошибку при компиляции:
javac -Xlint:unchecked Node.java
Node.java:21: error: incompatible types: String cannot be converted to CAP#1
other.value = node.value;
^
where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ?
1 error
Итак, как вы можете видетьнеограниченный подстановочный знак предлагает лучшие гарантии проверки типов, чем необработанный тип.