I cooked up a toy Java 5 class that generates warnings of the "unchecked" family when compiled:

package pholser.util;

import java.util.Arrays;

public class Stack<T> {
    private final Object[] storage;
    private int top;

    public Stack() {
        this.storage = new Object[ 5 ];
    }

    public Stack( final Stack<T> other ) {
        this.storage = (Object[]) other.storage.clone();
        this.top = other.top;
        final T currentTop = (T) storage[ top ];
    }

    public void push( final T item ) {
        checkPrecondition( isFull(), "can't push a full stack" );

        storage[ top++ ] = item;
    }

    public T pop() {
        checkPrecondition( isEmpty(), "can't pop an empty stack" );

        return (T) storage[ --top ];
    }

    public T peek() {
        checkPrecondition( isEmpty(), "can't peek an empty stack" );

        return (T) storage[ --top ];
    }

    @Override
    public boolean equals( final Object that ) {
        if ( this == that )
            return true;

        if ( that == null || !getClass().equals( that.getClass() ) )
            return false;

        final Stack<?> other = (Stack<?>) that;
        return top == other.top && Arrays.deepEquals( storage, other.storage );
    }

    @Override
    public int hashCode() {
        int hashValue = 17;
        hashValue = 37 * hashValue + top;
        hashValue = 37 * hashValue + Arrays.deepHashCode( storage );

        return hashValue;
    }

    private void checkPrecondition( final boolean precondition, final String message ) {
        if ( !precondition )
            throw new IllegalStateException( message );
    }

    private boolean isEmpty() {
        return top == 0;
    }

    private boolean isFull() {
        return top == storage.length;
    }
}

This yields the following warnings when compiled (Sun javac 1.5.0_06):

    [javac] C:\java\scratchpad\src\pholser\util\Stack.java:16: warning: [unchecked] unchecked cast
    [javac] found   : java.lang.Object
    [javac] required: T
    [javac]         final T currentTop = (T) storage[ top ];
    [javac]                                         ^
    [javac] C:\java\scratchpad\src\pholser\util\Stack.java:28: warning: [unchecked] unchecked cast
    [javac] found   : java.lang.Object
    [javac] required: T
    [javac]         return (T) storage[ --top ];
    [javac]                           ^
    [javac] C:\java\scratchpad\src\pholser\util\Stack.java:34: warning: [unchecked] unchecked cast
    [javac] found   : java.lang.Object
    [javac] required: T
    [javac]         return (T) storage[ --top ];

Note that each of the casts we attempt should be legitimate; if Java's type system is sound, there should be nothing but elements of at least type T in the Stack's storage.

I then attempted to suppress the warnings by applying the @SuppressWarnings( "unchecked" ) annotation to various elements of the class. Firstly, applying it to the class itself should do the trick:

@SuppressWarnings( "unchecked" )
public class Stack<T> {

Sure enough, no warnings. However, to quote the javadoc for @SuppressWarnings:

As a matter of style, programmers should always use this annotation on the most deeply nested element where it is effective. If you want to suppress a warning in a particular method, you should annotate that method rather than its class.

Fair enough. Tacking the annotation on the declarations of pop() and peek():

@SuppressWarnings( "unchecked" )
    public T pop() {

@SuppressWarnings( "unchecked" )
    public T peek() {

suppresses the warnings on those methods. We should do the same for the "copy" constructor:

@SuppressWarnings( "unchecked" )
    public Stack( final Stack<T> other ) {

Golden. It's nice to be able to apply @SuppressWarnings to so many different kinds of program elements. We've seen it applied so far at the class, method, and constructor level.

By un-inlining ("out-lining?") the return values of pop() and peek(), and the local currentTop in the "copy" constructor, we can show off application of @SuppressWarnings on locals:

        @SuppressWarnings( "unchecked" )
        final T currentTop = (T) storage[ top ];

        @SuppressWarnings( "unchecked" )
        final T returnValue = (T) storage[ --top ];
        return returnValue;

Would an astute reader be so kind as to augment this example to demonstrate how @SuppressWarnings can effectively stifle "unchecked"-flavored warnings on fields or parameters? Marking the that parameter of Stack.equals() and then attempting a dubious cast of that to Stack<T> didn't stifle the warning. Also, marking field storage didn't prevent warnings, perhaps because the program element in question in pop(), peek(), and the copy ctor is an element of an array field, not the array field itself.

In Jaggregate there were a few spots in the code that were generating "unchecked"-flavored warnings--about 20 or so--even though it was demonstrable that the code was correct and would not lead to bad casts. Once @SuppressWarnings became supported in Java 5 update 6, I undertook an effort to eliminate and/or suppress the remaining warnings. I found that pretty much all of these warnings were in places where I was attempting a cast to a generic type. Marking methods and local variables with @SuppressWarnings( "unchecked" ) did the trick but seemed to clutter up the code quite a bit. So, I refactored the casts to a method:

    class Objects {
        @SuppressWarnings( "unchecked" )
        static <T> T cast( final Object target ) {
            return (T) target;
        }
    }

Now that's minimizing the scope of the suppression. 8^)

So now, instead of:

    @SuppressWarnings( "unchecked" )
    private void repopulateBucket( final Object bucket ) {
        for ( Node<K, V> node = (Node<K, V>) bucket;
            node != null;
            node = node.nextNode ) {

            put( node.key(), node.value() );
        }
    }

or

    private void repopulateBucket( final Object bucket ) {
        for ( @SuppressWarnings( "unchecked" ) Node<K, V> node = (Node<K, V>) bucket;
            node != null;
            node = node.nextNode ) {

            put( node.key(), node.value() );
        }
    }

we have:

    private void repopulateBucket( final Object bucket ) {
        for ( Node<K, V> node = Objects.cast( bucket );
            node != null;
            node = node.nextNode ) {

            put( node.key(), node.value() );
        }
    }

Note how the type inference on generic methods really helps--we don't have to tell the compiler what we want to cast to, it's kind of a no-brainer in this case. In other cases, especially when trying to cast to a type specified by a type parameter, you have to give the compiler a hint:

    public E at( final int index ) {
        checkIndexIsValid( index, "search" );

        return Objects.<E>cast( storage[ index ] );
    }

It's not crystal clear to me what are the exact circumstances that require the extra hint, but in any event I was able to suppress the warnings in the Jaggregate code with a minimum of clutter.