“b4” é autoboxed, portanto é um objeto à parte.
“b1==b4” somente retornaria “true” caso fizessem referência ao mesmo objeto.
“b1==b3” retorna “true” pois ao comparar um tipo Wrapper a um primitivo, o Wrapper é unboxed e neste caso se comportam como em uma comparação entre dois booleans primitivos de valor “true”.
Isso cai em provas de certificação? Cruz credo. Não caiu nada parecido na minha.
De qualquer maneira, ao compararmos b1 e b3, o compilador faz o seguinte:
a) b1 é convertido para um boolean (primitivo), valendo true
b) b1 (primitivo, true) == b3 (primitivo, true) retorna true.
Ao compararmos b1 e b4, o compilador faz o seguinte:
a) b1 e b4 são ambos java.lang.Boolean (wrappers), portanto podem ser comparados diretamente, como objetos.
b) b1 é um novo objeto Boolean (criado com “new”), enquanto escrever “Boolean b4 = true” é equivalente a escrever “Boolean b4 = Boolean.TRUE”, ou seja, você pega um dos dois objetos Boolean.FALSE ou Boolean.TRUE que são estáticos e já foram criados pela JVM antes de você iniciar seu programa.
Então b1 não é o mesmo objeto que b4, portanto b1 == b4 retorna false.