This is the point, AFAICT. In languages with both primitive "read/write field" operations that can't be interceded upon, but also with interfaces/protocols, "obfuscating" (encapsulating) a field access in getter/setter methods is how you allow for alternative implementations of the interface/protocol.
Specifying your object's interface in terms of getters/setters allows for objects that satisfy your interface but which might:
• read from another object (flyweight pattern)
• read from another object and return an altered value (decorator pattern)[1]
• read from an object in a remote VM over a distribution protocol (proxy pattern)
Etc.
Then a client can build these things and feed them to your library, and you won't know that they're any different than your "ordinary" data objects.
You don't see this in languages with "pure" message-passing OOP, like Ruby or Smalltalk, because there's no (exposed) primitive for field access. All field access—at the AST level—goes through an implicit getter/setter, and so all field access can be redefined. But in a language like Java, where field access has its own semantics divorced from function calls, you need getters/setters to achieve a similar effect.
And yes, this can cause problems—e.g. making expected O(1) accesses into O(N) accesses, or causing synchronous caller methods to block/yield. This is why languages like Elixir, despite having dynamic-dispatch features, have chosen to discourage dynamic dispatch: it allows someone reading the code to be sure, from the particular function being called, what its time-and-space-complexity is. You know when you call MapSet.fetch that you're getting O(1) behaviour, and when you call Enum.fetch that you're not—rather than just accessing MapSets through the Enum API and having them "magically" be O(1) instead of O(N).)
---
[1] Which is a failure of the Open-Closed Principle. That doesn't stop people.