Almost everything is explained by Edward in his comment to the question. I will add just a bit.
This is a pretty interesting discussion of the rationale for different access modifiers:
Pay attention for description of cases where different access for read and assignment operations can be useful. It is often used in C++, C#, Delphi Pascal, etc.
By the way, I would advice not to forget
access modifiers which defined access
if accessed withing the package and like
when accessed across packages. The idea is this: you should not provide more access than it is really needed.
I should also note that the common practice is to use getters or setters even when the access methods are trivial and logically equivalent to using just the fields. In this case, these method just provide a clue that a public/internal getter/setter interface is abstracted from the (private) data structure, and non-trivial access (get or set) algorithms can be added at any moment later. Ideologically, this is similar to using empty base classes or interfaces: they just carry some semantic representing the elements of reality and named according to a denotation
taken from natural language; it also serves as a placeholder for the class or interface member which may help to express the semantics during later development. This is a way of using computer language syntax in order to support not only the run-time semantics of code, but the process of development.
Finally, I want to note on the following part of the question:
Chrene91 wrote:Should I just skip the encapsulation and just go with public fields…?
It is apparent that you are trying to use the term encapsulation
in some very narrow sense which is neither default nor customary. Usually, the implied sense of this term in OOP does not allow you to "skip encapsulation" as soon as you simply use classes in any sensible way. It generally means information hiding
understood in terms of code maintenance and discipline. Please see: