As others have said, == compares references while .equals compares values.
== is faster than .equals, but if more than one instance of an object can have the same value and you are comparing the values, you can't use == and expect it to be right. If the two objects are a different instance, but have the same value, == will return false.
That said, there are some immutable objects that implement "instance control".
They do this using a static factory method. The class will define a static Map of instances of all the objects of itself that have been created. The static factory method will instantiate an object with the parameters passed to it. But, before returning the object, it checks the Map to see if it has an object of the same value.
If it finds one that is equal, it returns the object in the Map that has the same value instead of the newly created object.
If it does not find an object that is equal, it adds the newly created object to the Map and returns the new object.
The advantage of this is that, for objects that implement instance control, it is safe to use == to check for value equality because there is no way that two objects with the same value will ever exist.
Effective Java discusses instance control in Chapter 2.
Guava has classes called Interners that make it trivial for a class that wants to implement instance control to do so by storing objects of itself in the Interner construct.
Immutable objects that implement instance control like this should indicate that they do in their documentation. If they do, you know it is safe to use == to check for value equality. But, for any immutable objects that do not implement instance control, you should always use .equals to check for value equality.