I want to add my 2 cents on using == with interned strings.
The first thing String.equals does is this==object.
So although there is some miniscule performance gain ( you are not calling a method), from the maintainer point of view using == is a nightmare, because some interned strings have a tendency to become non-interned.
So I suggest not to rely on special case of == for interned strings, but always use equals as Gosling intended.
EDIT: interned becoming non-interned:
V1.0
public class MyClass
{
  private String reference_val;
  ...
  private boolean hasReferenceVal ( final String[] strings )
  {
    for ( String s : strings )
    {
      if ( s == reference_val )
      {
        return true;
      }
    }
    return false;
  }
  private void makeCall ( )
  {
     final String[] interned_strings =  { ... init with interned values ... };
     if ( hasReference( interned_strings ) )
     {
        ...
     }
  }
}
In version 2.0 maintainer decided to make hasReferenceVal public, without going into much detail that it expects an array of interned strings.
V2.0
public class MyClass
{
  private String reference_val;
  ...
  public boolean hasReferenceVal ( final String[] strings )
  {
    for ( String s : strings )
    {
      if ( s == reference_val )
      {
        return true;
      }
    }
    return false;
  }
  private void makeCall ( )
  {
     final String[] interned_strings =  { ... init with interned values ... };
     if ( hasReference( interned_strings ) )
     {
        ...
     }
  }
}
Now you have a bug, that may be very hard to find, because in majority of cases array contains literal values, and sometimes a non-literal string is used.  If equals were used instead of == then hasReferenceVal would have still continue to work.  Once again, performance gain is miniscule, but maintenance cost is high.