I think the answer is simple. When the compiler can be 100% sure of the number you put in a byte, all assignments can be done compile time and casting will be done automatically.
"byte b=10" will compile because the compiler implicitly casts between the int 10 and the byte because it knows that no loss can occur. Since final variables are like conatants, the compiler knows that whenever a final int has gotten a value, it can be treated as a literal from then on. When the int is not final this should now work because the compiler doesn't feel confident the value will still be 10 by the time it gets to the byte assignment.
You should try to put the final int statement AFTER the byte assignment. This should work as well!