There's a striking difference here.
valueOf is returning an Integer object, which may have its values cached between -128 and 127. This is why the first value returns true - it's cached - and the second value returns false - 128 isn't a cached value, so you're getting two separate Integer instances.
It is important to note that you are comparing references with Integer#valueOf, and if you are comparing a value that is larger than what the cache supports, it will not evaluate to true, even if the parsed values are equivalent (case in point: Integer.valueOf(128) == Integer.valueOf(128)). You must use equals() instead.
parseInt is returning a primitive int. This is why the third value returns true - 128 == 128 is evaluated, and is of course, true.
Now, a fair bit happens to make that third result true:
- An unboxing conversion occurs with respect to the equivalence operator you're using and the datatypes you have - namely, int and Integer. You're getting an Integer from valueOf on the right hand side, of course.
- After the conversion, you're comparing two primitive int values. Comparison happens just as you would expect it to with respect to primitives, so you wind up comparing 128 and 128.