Para quem deve ter feito o teste e nao consegue entender a razao do resultado, a explicacao eh simples:
Em Java, o operador de igualdade ( == ) quando aplicado a objetos, compara as referencias do objeto, e nao a igualdade baseada no conteudo deles. Baseado nisso, se for prestado atencao, alguem poderia dizer: “mas porque entao a comparacao str1 == str2 retorna true???”.
Essa eh uma, digamos assim, regra as excessoes. Objetos do tipo String sao armazenados em um lugar chamdo “pool de string”, que a finalidade basica eh poder realizar algum aproveitamento de memoria no programa.
Quando fazemos
a string “ola” eh coloca no pool de strings e tem a sua referencia armazenada na variavel “str1”. Quando o codigo
eh executado, o compilador “ve” que ja tem uma string igual no pool de strings e entao, ao inves de criar um novo objeto e associar uma nova referencia a “str2”, ele simplesmente usa a referencia do “Ola” ja existente no pool, economizando assim memoria.
Por serem referencias iguais, a comparacao
retorna true.
Agora, quando fazemos
String str3 = new String("Oi");
String str4 = new String("Oi");
estamos dizendo ao Java “Java, eu tenho CERTEZA que quero dois objetos diferentes, entao nao use o pool de Strings”, e entao sao criados 2 objetos diferentes, o que resulta em referencias diferentes, levando a comparacao de igualdade retornar false.
As comparacoes usando o metodo “equals” retornam “true” porque este metodo compara o conteudo contido nos objetos, e nao as referencias.
Por isso que dizem que, para verificar se 2 objetos tem conteudos iguais, deve ser usado o metodo “equals”.
Basicamente eh isso 
Rafael