Se quiser ficar ainda mais confuso, faça o mesmo exercício mas troque o valor 12 por 1000 e se surpreenda 
A explicação aqui é que == envolvendo objetos, sejam eles quais for (Integer, String, ContaCorrente etc) sempre comparam referências. Então quando você dá new você me explicitamente dois objetos diferentes, cada um em sua referência, e aí é óbvio que == vai dar false.
Mas aí você se pergunta: porque o 1o caso dá true? Ele compara valor? Não, nunca. O == sempre compara referências. Só que no primeiro caso as referências são a mesma por uma combinação de fatores, e portanto o resultado é true.
Para entender é importante saber o que faz o autoboxing do Java 5. Ele não dá new explicitamente (ou seja, o 1o caso é diferente do 2o caso). O autoboxing sempre usa Integer.valueOf para embrulhar o valor. Na pratica, essas duas expressoes são equivalentes:
Integer i = 12;
Integer i = Integer.valueOf(12);
Por fim, sabendo disso, se voce ler o javadoc do valueOf vai quer que nem sempre esse método cria novos objetos. Ele pode ter um cache interno de Integers mais usados e apenas devolver a mesma referência se for pedido mais de uma vez. Aqui voce ja deve ter desconfiado que é exatamente o que acontece ao atribuir 12 a duas varias diferentes: ele devolve o mesmo objeto e temos duas referencias para o mesmo objeto.