Because such a class object can have a lifetime longer than the stack frame of the method that created it, the local variables that existed when the object was created may not exist later in the object's life. Therefore, what the
Java compiler does behind the scenes is give the class member variables to hold the values of the final local variables and copies the values of the final locals into the members. This gives the illusion that the object is accessing the final locals of the method, but really it's using its own members, which can last longer than the local variables do. The illusion would be spoiled if you could do this with non-final variables, as when their values changed, the member variables would not.