Because the moment you do something like 
public float returnSomething(String theThing) {
    switch (theThing) {
        case "height":
            return height;
        case "rotation" :
            return  rotation;
        case "width":
            return  width;
        default:
            return 0;
    }
}
I can feel the next question for Stack Overflow, "Why is my height always 0?"
And then post code like
public class GameThingy {
      //...
     private void doStuff(GameObject gameObject) {
         float gravity = 5*gameObject.returnSomething("hieght");
         gameObject.setSomething("velocyty", gravity+50);
     }
}
Technically the moment you make a typo anywhere, you'll have issues finding the source of the problem. That, and you're lucky that the fields are all float, they don't have to be.
Edit: By the way, this is actually a typical problem in defining the field of interest in some database queries. As in, having to specify the field you're looking for by a String. 
A real-life example is RealmQuery<T>.
A RealmQuery<T> looks like this:
RealmQuery<User> query = realm.where(User.class);
// Add query conditions:
query.equalTo("name", "John");
// Execute the query:
RealmResults<User> result1 = query.findAll();
Where they assume the class User is something like this:
public class User {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
An interesting note is that Realm creates a "proxy subclass" where they redefine the setName and getName methods (aka, you need getters/setters to make some systems work! They assume you have them!)
But what's important here is that you need to provide the field name with "name".
Later on, anyone can make a typo, or you just won't remember the fields off the top of your head. In this particular case, they tend to create a metamodel (something that stores the name of the fields for you) for the purpose that you won't have to use Strings to refer to field names.
For example, in Criteria API, instead of
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet.get("name"));
They have the metamodel like this:
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet.get(Pet_.name));
Thus, it eliminates the need for Strings.
And similarly, what I tend to do with Realm is that I create a "metamodel" (although you can now have it generated for you automatically with RealmFieldNamesHelper):
public class User
        extends RealmObject {
    @PrimaryKey
    private long id;
    private String name;
    public static enum Fields { //this is the "metamodel"
        ID("id"),
        NAME("name");
        private String fieldName;
        Fields(String fieldName) {
            this.fieldName = fieldName;
        }
        public String getField() {
            return fieldName;
        }
        @Override
        public String toString() {
            return getField();
        }
    }
}
And thus you can replace the query like so
RealmResults<User> result2 = realm.where(User.class)
                                  .equalTo(User.Fields.NAME.getField(), "John")
                                  .or()
                                  .equalTo(User.Fields.NAME.getField(), "Peter")
                                  .findAll();
But with getters and setters, you already have the type safety, and you already have the methods that you don't have to remember off the top of your head - and so, you have the compilation time error checks.
So to answer your question, the reason why it's a bad practice to refer to variables by string name in Java is because
1.) typos can happen, and the error occurs only in runtime, not compile time
2.) it is not type-safe; you are lucky that you get floats back no matter what in this example, but the moment it can be a String, you need to return Object and cast it or use public <T> T get(String field) { ... } and whoever calls the method must know exactly what they are receiving - also runtime-error prone.