Related
A colleague of my says that this is data encapsulation and it has to be done when using database access:
public String foo(final int x) {
return fooHidden(x);
}
private String fooHidden(final int x) {
return db.lookFor(x);
}
I simplified the code to be more readable, but it's still the same structure.
So in my opinion this is not data encapsulation, it doesn't hide anything, because the return value and the transfer parameter are equal. So for me, it would make no difference to write:
public String fooHidden(final int x) {
return db.lookFor(x);
}
The upper solution would make sense for me if we overlay the method or have other parameters for the private method which use class internal attributes, but this is not the case.
Can you tell me who is right? How would you accomplish real data encapsulation for this case?
The two methods implementations are quite the same, i.e. in your case it makes no difference, but semantically speaking, it would make more sense to have:
public String foo(final int x) {
return db.lookFor(x);
}
Note the name foo and not fooHidden to make reference to publicly provided method (hidden would otherwise imply you are exposing a supposed-to-be-private method).
Meanwhile, both implementation still hide the db field, which should be hidden from class callers and private to the wrapping class, hence encapsulated.
So encapsulation is about the field state and not the method implementations.
This implies that the class structure should be as follows in a whole:
public class MyClass {
private db; // must be private, otherwise you'll be violating the encapsulation rule
public String foo(final int x) {
return db.lookFor(x);
}
}
Going back to the OP question:
Do I always have to write public methods + private methods?
The question should instead be: Do I always have to write public + private fields?
And I would state that in major cases, you should do it yes.
Meanwhile, there may be design requirements that need to have the rule broken.
Encapsulation, in Java, is about Access Modifiers; meaning what fields / methods you make public thus accessible for the outside world.
Here is what what Martin Fowler states about Access Modifiers:
Object-oriented languages divide a program into modules called classes. Each class contains features, which consist of data (fields) and methods. (Not all languages use these terms, but they'll do for this.) Languages have various rules about what other classes can access the features of a class, these are often based on access modifiers that apply to a class.
I know lots of coders use accessor methods to access some class fields which are private from other classes, but I was wondering why. And why they don't prefer protected fields witch are accessible only from classes of the same package instead of accessors? I mean if there is not a serious reason, it's just code waste.
When you only define methods to access a field, you are restricted by the methods. You cannot do something that there is not a method for.
Consider this class:
public class Account {
private int balance = 0;
public int getBalance() {
return balance;
}
public void insert(int amount) {
if(amount > 0) {
balance += amount;
}
}
public void withdraw(int amount) {
if(amount > 0 && amount =< balance) {
balance -= amount;
}
}
}
You can change the balance of the account by inserting and withdrawing, and you can check what it is. But if you had access to the balance directly, you could do something that is not supposed to be possible like:
Account acc = new Account();
acc.balance = -10;
Furthermore, protected is actually closer to public than to private. If you have a private field, it will be private forever. If your field is protected, anyone can always extend your class and access the field. If it is intended to be private and you set it to protected, it might lose its purpose when someone extends it (and the fact that he extended no longer makes sense, because his new class does not behave in the spirit of the superclass).
A mutuator method like a getter or a setter is not the same thing as a protected variable.
You have no control on when a protected variable is read or written if who is accessing it has the right to access it but a mutuator works as a bridge which is able to intercept modifications or access to an underlying member attribute and also provide different behavior from just returning/setting the value. So they don't fulfill exactly the same purpose.
In addition with mutuators you are able to provide a read-only or write-only access to a private member variable, but you can't do it with a protected field.
Using accessors/mutators methods is a common best practice in Java programming as in other languages.
Wikipedia suggests:
The mutator method is most often used in object-oriented programming, in keeping with the principle of encapsulation. According to this principle, member variables of a class are made private to hide and protect them from other code, and can only be modified by a public member function (the mutator method), which takes the desired new value as a parameter, optionally validates it, and modifies the private member variable.
So you use accessors to hide the logic (if present) applied before setting or getting the private variable value.
protected modifier instead should be used to mark variables (or methods) that are not inteded to be publicly accessible, but that should be inherited and visible by sub classes. The sub class can use this variable in its methods and/or it can expose it publicly via accessors if necessary.
I try to understand a lot of times but I failed to understand this.
Encapsulation is the technique of making the fields in a class private
and providing access to the fields via public methods. If a field is
declared private, it cannot be accessed by anyone outside the class,
thereby hiding the fields within the class.
How can we change the values of fields through setter methods? How do we prevent accessing the fields directly? What is the real use of encapsulation?
Assume you have an age property.
The user can enter a value of -10, which although is a valid number, is an invalid age. A setter method could have logic which would allow you to catch such things.
Another scenario, would be to have the age field, but hide it. You could also have a Date of Birth field, and in it's setter you would have something like so:
...
private int age
private Date dob
...
public void setDateOfBirth(Date dob)
{
this.dob = dob;
age = ... //some logic to calculate the age from the Date of Birth.
}
I have also been confused like you too for a long time until I read the book Encapsulation and Inheritance in Object-Oriented Programming Language and a website that explained the importance of Encapsulation. I was actually directed from the website to the book.
People always say encapsulation is "hiding of information" therefore, maybe, making encapsulation focus on security as the main use. Yes you are hiding information in practice, but that should not be the definition as it could confuse people.
Encapsulation is simply "minimizing inter-dependencies among separately-written modules by defining strict external interfaces" (quoting from the book). That is to say that when I am building a module, I want a strict contract between my clients and me on how they can access my module. Reason being that, I can improve the inner workings without it AFFECTING my client's, life, application or whatever they are using my module for. Because their "module" does not exactly depend on the Inner workings of my module but depends on the "external interface", I made available to them.
So, if I don't provide my client with a setter and give them direct access to a variable, and I realize that I need to set some restriction on the variable before my client could use it, me changing it, could be me, changing the life of my client, or application of my client with HUGE EXPENSE. But if I provided the "strict contract" by creating a "strict external interface" i.e setter, then I can easily change my inner workings with very little or no expense to my clients.
In the setter situation (using encapsulation), if it happens that when you set a variable, and I return a message informing you that it has been assigned, now I could send a message via my "interface", informing my client of the new way my module have to be interacted with, i.e "You cannot assign negative numbers" that is if my clients try to assign negative number. But if I did not use encapsulation, and gave my client direct access to a variable and I do my changes, it could result in a crashed system. Because if the restriction I implemented, is that, you could not save negatives and my client have always been able to store negatives, my clients will have a crashed system in their hands (if that "crashed system" was a banking system, imagine what could happen).
So, encapsulation is more about reducing dependency between module, and an improvement can be made "quietly" with little or no expense to other modules interacting with it, than it is of security. Because the interacting modules depend on the "strict external interface or strict contract".
I hope this explains it properly. If not you could go the links below and read for yourself.
encapsulation matters
Encapsulation and Inheritance in Object-Oriented Programming Languages
The real use of encapsulation is also in the fact that you can do additional checks/processing on the way the values are set.
You're not exactly preventing access to the fields -- you're controlling how others can access certain fields. For example you can add validation to your setter method, or you can also update some other dependent field when the setter method of a field is called.
You can prevent write or read access to the field (e.g. by only providing a getter or setter respectively) -- but encapsulation with properties allows you to do more than just that.
If you have private fields they can't be accessed outside the class, that means basically those fields don't exist to the outside world and yes you can change their value through setter methods but using setter methods you have more flexibility/control to say who gets to change the fields and to what value can they be changed to...basically with encapsulation you get to put restrictions on how and who changes your fields.
For example you have: private double salary, you setter method could restrict that only hr staff can change the salary field it could be written as:
void setSalary(Person p,double newSalary)
{
//only HR objects have access to change salary field.
If(p instanceof HR && newSalary>=0)
//change salary.
else
S.o.p("access denied");
}
Imagine if salary was public and could be access directly any can change it however and whenever they want, this basically the significance of encapsulation
The main idea behind encapsulation is data hiding. There are several reasons why we use encapsulation in object oriented programming. Some of the identified reasons for why we encapsulation are as follows (The real use of encapsulation).
Better maintainability: When all the properties are private and encapsulated, it is easy for us to maintain the program simply by changing the methods.
Make Debugging Easy: This is in line with the above point. We know that the object can only be manipulated through methods. So, this makes it easy to debug and catch bugs.
Have a Controlled Environment: Let the users use the given objects, in a controlled manner, through objects.
Hide Complexities: Hiding the complexities irrelevant to the users. Sometimes, some properties and methods are only for internal use and the user doesn't have to know about these. This makes is simple for the user to use the object.
So, to answer the question, "What is the use of encapsulation when I'm able to change the property values with setter methods?", given above are some of the main reasons why we use encapsulation. To provide an understanding on why, getters and setters are useful, given below are some important points, obtained from this article.
You can limit the values that can be stored in a field (i.e. gender must be F or M).
You can take actions when the field is modified (trigger event, validate, etc).
You can provide thread safety by synchronizing the method.
You can switch to a new data representation (i.e. calculated fields, different data type)
Any how i am able to change the values of fields through setter methods.
Only if the setter method lets you do that.
How we are preventing the accessing fields?
The setter and getter get to control if and how you can access the fields.
A setter may check if the value is valid. It may ask a SecurityManager if you should be allowed to do this. It may convert between data types. And so on.
Lets suppose you make a custom Date class with the following setters / getters:
getDay()
getMonth()
getYear()
setDay()
setMonth()
setYear()
Internally you could store the date using:
private int day;
private int month;
private int year;
Or you could store the date using a java.lang.Date-object:
private Date date;
Encapsulation doesn't expose how your class is working internally. It gives you more freedom to change how your class works. It gives you the option to control the access to your class. You can check if what the user enters is valid (you don't want the user to enter a day with a value of 32).
It's aim is nothing but protecting anything which is prone to change. You have plenty of examples on the web, so I give you some of the advantages of it:
Encapsulated Code is more flexible and easy to change with new requirements
Allows you to control who can access what. (!!!)
Helps to write immutable class in Java
It allows you to change one part of code without affecting other part of code.
Accessing fields thru methods make difference because it makes it OOP. Eg you can extend you class and change the behaviour which you cannot do with direct access. If you have getters / setters you can make a proxy of your class and do some AOP or a make a 1.4 dynamic proxy. You can make a mock from your class and make unit testing...
Encapsultaion is used for hiding the member variables ,by making member as private and access that member variable by getter and setter methods.
Example
class Encapsulation{
private int value ;
Encapsulation() {
System.out.println("constructor calling ");
}
void setValue(int value){
this.value = value;
}
int getValue() {
return value;
}
}
class EncapsulationMain {
public static void main(String args[]) {
Encapsulation obj = new Encapsulation();
obj.setValue(4);
//System.out.print("value is "+obj.value);
//obj.value = 55;
//System.out.print("obj changing the value"+obj.value);
System.out.print("calling the value through the getterMethod"+obj.getValue());
}
}
you cannot access the private value outside the class.
Well, encapsulation is not all about hiding data. It is all about getting control over what is stored in the fields. Using encapsulation we can make a field as read-only or write-only depending upon the requirements.Also the users don't know how the data is stored in the fields. We can use some special encryption in the setter methods and store it in the fields.
For example human is a object. We only require the name field of the human to be read by the user but not to be modified. Then we define only get method on the name field.This is how the encapsulation is useful.
If you have class all of its properties are private-meaning that they cannot be accessed from outside the class- and the only way to interact with class properties is through its public methods.
You are changing tha values by giving the public access to those methods(setters).
using encapsulation the fields of a class can be made read-only or write-only.
Instead of letting everyone access the variables directly:
public Object object;
Is better to use SET and GET methods, or for example just the GET method (Sometimes you dont want nobody to set other value to that variable).
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
By using encapsulation you separate your class from the out-side world (other classes) and out-side world can access and modify your class instance variables through access modifiers, which provides several benefits:
-You can do some logging in your getter/setter methods.
-You can validate /normalize (for example trim spaces, remove special character,...) Your input in setter method.
And also you can hide your implementation from the outside world, for example you have a collection like array list in your class and you write your getter method like this
public List<t> get collection(){
return new ArrayList<t>(this.arrayList);
}
So in this case, in the future if you decide to change your implementation of collection from array list to something else like linked list, you are free to do so because out side world doesn't know anything about your implementation.
Encapsulation is not about secrecy, it is about reducing dependency over separate part of the application.
We control dependency (loose / weak / low coupling) by hiding information over separate part of the application.
Adding to Uche Dim's answer, look at the following example:
Two Connections:
public class Area {
// fields to calculate area
private int length;
private int breadth;
// constructor to initialize values
Area(int length, int breadth) {
this.length = length;
this.breadth = breadth;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getBreadth() {
return breadth;
}
public void setBreadth(int breadth) {
this.breadth = breadth;
}
public int getArea() {
int area = length * breadth;
return area;
}
}
class Main {
public static void main(String[] args) {
Area rectangle = new Area(5, 6);
// Two Connections
int length = rectangle.getLength();
int breadth = rectangle.getBreadth();
int area = length * breadth;
System.out.println("Area: " + area);
}
}
Please note that in the Main class, we are calling two methods (getLength() and getBreadth()) of Area class.
One Connection:
public class Area {
// fields to calculate area
private int length;
private int breadth;
// constructor to initialize values
Area(int length, int breadth) {
this.length = length;
this.breadth = breadth;
}
public int getArea() {
int area = length * breadth;
return area;
}
}
class Main {
public static void main(String[] args) {
Area rectangle = new Area(5, 6);
// One Connection
int area = rectangle.getArea();
System.out.println("Area: " + area);
}
}
Here, in the Main class, we are calling one methods (getArea()) of Area class.
So in the second example, the connection is weaker than the previous one (first one calling two methods or the Area class, second one calling one method of the Area class). Given, less connection (lower / weaker coupling) is better, the second example is better.
We should always keep fields and methods private unless necessary. In the Two Connections example, we made the mistake of creating the getters unnecessarily. As we have created it, the IntelliJ Idea (auto suggestion of modern IDE) suggested the developer who was working on the Main class that you can use the getLength() and getBreadth() methods and he did. He did not inquire further to check if there was a getArea() method. As a result he created stronger coupling than necessary.
We should not unnecessarily create getters. We should not unnecessarily make fields public or protected. If you must, first try protected, if that does not work then make it public. That way we will have a lesser possibility of having a tighter coupling.
If you still have the question "what is the difference between making a field public compared to making a field private but it's getters public?", in other words "Why should we use a function to get a value instead of getting it directly?" Well it gives you another layer of abstraction. For example, if you need some extra processing of the data before receiving it (ex. validation), you can do it there. Moreover, once you expose internals of a class, you can not change that internal representation or make it better until making changes in all client codes.
For example, suppose you did something like:
public class Area {
private int length;
private int breadth;
}
class Main {
public static void main(String[] args) {
Area rectangle = new Area(5, 6);
int area = rectangle.length * rectangle.breadth;
System.out.println("Area: " + area);
}
}
Now, if you want to change breadth to width in Area class, you can not do it without breaking the program, unless you search and replace rectangle.breadth with rectangle.width in all the clients where rectangle.breadth was used (in this case Main class).
There are other benefits as well. For example, Member variables cannot be overridden like methods. If a class has getters and setters, it's subclass can override these methods and return what makes more sense in the context of subclass.
Please check Why getter and setter are better than public fields in Java? for more details.
P.S. These are trivial examples, but in large scale, when program grows and frequent change requests are a reality, this makes sense.
I'm OK with using get and set, to mask and make reengineering easier, but if you tell to a novice programmer that using get and set does encapsulation, as I've seen many times, they will use set and get for internal members initialized by the constructor.
And this 99.9 % is wrong!!!!!
private uint8_t myvar = 0;
setMyVar(uint8_t value){
this.myvar = value * (20 / 41);
}
uint8_t getMyVar(){
return this. myvar ;
}
That’s for me is ok, but I think encapsulation is a method first, rather than get and set.
My inglish is not very well,but I think that this article says something like this.
In some domain object's method , they didn't use the attribute directly, but use the get method . Why ? One example as follows:
private List<String> errorCodeList = new ArrayList<String>();
/**
* Add all errors to the error list.
*/
public void addAllErrors(Collection<String> theErrorStrings) {
if (errorCodeList == null) {
errorCodeList = new ArrayList<String>();
}
for (String aString: theErrorStrings) {
getErrorCodeList().add(aString);
}
}
/**
* #return the errorCodes
*/
public List<String> getErrorCodeList() {
return errorCodeList;
}
/**
* Set the error strings.
*/
public void setErrorCodeList(List<String> allErrors) {
this.errorCodeList = allErrors;
}
It's a matter of encapsulation. By providing access to instance variables only via getters and setters you hide the internal representation. Thus you are able to change the implementation afterwards without modifying the interface. You might decide that it would be more convenient to use a HashMap to store the error codes (for whatever reason) and once you changed that, all code accessing the field would break. If you provided getter and setter however, you are able to keep them as they are in spite of your changed internal representation.
In addition to it is easier to ensure that invariants are kept in place, which you were unable to do if everybody could access the fields.
I'm personally not a fan of accessing fields within the same class via their getter methods: Encapsulation is not being broken by avoiding calling the getter because you're writing code within the same class definition. Also, using getters makes the code look more cluttered and doesn't provide effective syntax highlighting.
There are obviously exceptions where you have to access the field through a getter:
When it's lazily created.
When the getter calculates a value on the fly.
I think the sample code is not the best way to do it: the variable is being accessed directly and through the getter in the same method - this mixing is kind of confusing.
It would be clearer if the lazy creation of the list was done in the getter and a reason to use the getter. Example:
public void addAllErrors(Collection<String> theErrorStrings) {
for (String aString: theErrorStrings) {
getErrorCodeList().add(aString);
}
}
public List<String> getErrorCodeList() {
// TODO synchronization?
if (errorCodeList == null) {
errorCodeList = new ArrayList<String>();
}
return errorCodeList;
}
That is encapsulation:
Encapsulation can be described as a protective barrier that prevents
the code and data being randomly accessed by other code defined
outside the class. Access to the data and code is tightly controlled
by an interface.
More information available here.
It can be considered good practice to use a getter within a call is the getter exists. This is because if the implementation behind the getter were to change the rest of the code in the class that uses the getter would not need to change.
It also can ease static code analysis since all access to the field (either from within the class or without) are done via a single method.
There of course is the trade off of the extra method call (unless the compiler is smart enough to do the conversion).
That said, I agree with Adamski, I am not a fan of this either.
Encapsulation won't be broken by directly accessing data members, but what about, after a couple of month, a data member change semantics and you've got to search in one hundred derived classes where that field was accessed directly just to be sure that nothing breaks up ? If access is solely done via getter, it's a lot easier to track where each field is accessed.
I am programming a game in java, and as the question title suggestions i am using public fields in my classes. (for the time being)
From what i have seen public fields are bad and i have some understanding why. (but if someone could clarify why you should not use them, that would be appreciated)
The thing is that also from what i have seen, (and it seems logical) is that using private fields, but using getters and setters to access them is also not good as it defeats the point of using private fields in the first place.
So, my question is, what are the alternatives? or do i really have to use private fields with getters and setters?
For reference here is one of my classes, and some of its methods.
I will elaborate more if needs be.
public double health;
//The player's fields.
public String name;
public double goldCount;
public double maxWeight;
public double currentWeight;
public double maxBackPckSlts;
public double usedBackPckSlts; // The current back pack slots in use
public double maxHealth; // Maximum amount of health
public ArrayList<String> backPack = new ArrayList<String>();
//This method happens when ever the player dynamically takes damage(i.e. when it is not scripted for the player to take damage.
//Parameters will be added to make it dynamic so the player can take any spread of damage.
public void beDamaged(double damage)
{
this.health -= damage;
if (this.health < 0)
{
this.health = 0;
}
}
EDIT: For checking purposes, this is what my Weapon class looks like now: (Code sample is not working for some reason, so it does not look right.)
private final double DAMAGE;
private final double SPEED;
public Weapon(double initialDmg,double initialSpd,String startName,double initialWg)
{
DAMAGE = initialDmg;
SPEED = initialSpd;
setItemName(startName);
setItemWeight(initialWg);
}
public double getSpeed()
{
return SPEED;
}
public double getDamage()
{
return DAMAGE;
}
As you can see, as the Weapon's DAMAGE and SPEED do not need to be changed, they can be final's for the time being. (if, later in the game, i decided these values can be "Upgraded" so to speak, i may add setters then , with validation, or just make a new weapon with the upgraded values) They get set in the Weapon's constructor.
Conclusion: getters and setters are fine, as long as they are used smartly, and only used when needed. (however)
It's common to use getters and setters instead of giving other objects permission to change your fields directly. That might not make any sense when you see that 99.99% of your getters and setters don't do anything except what you could have done with direct access to the fields. But what happens when you decide that when a player is damaged beyond a point, he drops half his inventory? Or you want to restrict how many backpack slots can be used by magical items? You either have to hunt down all the places in your code where you modify the fields, or, if you used getters and setters, you make the changes entirely in the class. That's the heart of object oriented programming - that you've encapsulated "knowledge" of what an object does within the object itself, not spread it out among all the objects that interact with that object.
One of the core concepts of object-oriented programming is encapsulation -- that is, hiding an object's state (for example, the data in the object) from the outside, and letting the object handle it's own state.
When encapsulation is done well, the object's state can only be affected from the outside world through the interfaces provided by the object, such as methods the object has.
I think your code is already starting to use encapsulation.
Let's take a look at the code
Let's take a look at the beDamaged method.
public void beDamaged(double damage)
{
this.health -= damage;
if (this.health < 0)
{
this.health = 0;
}
}
Here's we can see that this method will be called by the outside world, and the player's health will be affected. It also contains logic, so the health cannot be a negative number. The player's beDamaged method that you wrote is keeping the state of the object within the parameters that you defined as being the valid state.
Let's infer something about the player
Now, from the above, I think I can infer the following about the player object:
A player's health cannot be a negative number.
Is what we inferred always true?
Let's see if this can always be true from the code you've provided.
Aha! We have a little problem here:
public double health;
With the health field being public, the outside world can directly manipulate the field in order to place the player object's state into one that is probably not desired, by some code like the following:
Player player = new Player();
player.health = -100
I'm going to guess that the player shouldn't be in a state where the health is a negative number.
What can we do about it?
How could that have been avoided? -- by having the health field private.
Now, the only way to affect the player's health would be through the beDamaged and gainHealth methods, and that's probably the right way for the outside world to affect your player's health.
Which also means this -- when you make a field private, that does not automatically mean that you should make getters and setters for the field.
Private fields does not necessitate getters and setters
Getters and setters are usually a way to directly affect a field that an object has, maybe with some validation to prevent bad input from making your object have a state that it shouldn't, but there are going to be times where the object itself should be in charge of affecting the data, rather than an outside entity.
In Java, using private fields with getters/setters is the recommend practice, provided external clients of your class really need access to those fields.
Otherwise keep them as private fields and simply don't provide a getter/setter.
There are various reasons why this is a best practice:
If clients are using your field directly and later something needs to change regarding that, you're stuck. With a getter you can do a whole lot of things before the field is accessed.
There is something called the JavaBeans specification that requires you to use getter/setters. Without them your class (then called bean) won't interoperate with that. JSP and JSF's EL is one example of something that required your class to comply with JavaBeans standards.
(p.s. unrelated to your question, but you'd better not declare backPack as an ArrayList. Declare as List; code to interface, not to implementation)
If you have a private field with a method get() and a method set() that don't do anything other than retrieve and assign the value, you should just make the field public, as the field isn't really private, and the getters and setters only hurt performance. If the getters and setters check the value being set or if the value is allowed to retrieve, then go ahead and use getters and setters. e.g. If you have a variable private int width; and someone tries to put in -1 with a setter, and the setter makes sure it isn't negative, then that is a good use. For example:
private int width;
public int get(){
return width;
}
public void set(int w){
if (w < 0) throw new RuntimeException();
else width = w;
}
This would be a good use of getters and setters. Otherwise, they hurt your performance if the only thing they do is assign or get the value without anything else.
So to make a long story short:
Use getters and setters when doing anything other than retrieving or assigning a value. Else, just use public fields.
i.e.
BAD:
private int width;
public int get(){
return width;
}
public void set(int w){
width = w;
}
GOOD:
private int width;
public int get(){
return width;
}
public void set(int w){
if (w < 0) throw new RuntimeException();
else width = w;
}
GOOD if you don't want anything other than getting or setting:
public int width;
About this:
The thing is that also from what i have seen, (and it seems logical) is that using private fields, but using getters and setters to access them is also not good as it defeats the point of using private fields in the first place.
The main problem is that many developers automatically generate getters and setters for all private fields. And if you're going to do that, I agree, you might as well keep the field public (no, public fields are even worse).
For every field that you have, you should check:
a) does it need a Getter (do other classes need to know the value of this field)
b) does it need a Setter (do other classes need to be able to change the value of this field)
c) or does the field need to be immutable (final), if so it must be initialized during definition or in the constructor (and it can obviously have no setter)
But you should hardly ever (exception: value objects) assume that all private fields will have getters and setters and let your IDE generate them all.
An advantage of using getters and especially setters is, that it is much easier to debug write access to the fields.
private fields and setters and getters is indeed your best way to go.
Further note that this is in general good code in any language as it keeps your security nice and tight while also giving you a structure that is far easier to debug and maintain. (Don't forget to document btw!)
All in all, go with setters and getters, it's just good practice even if you find options.
Getters and setters are part of the public interface of your class. It's a contract between the class designer/developer and the users of that class. When you define getters and setters, you should be committed to maintain them in future versions.
Attributes should only correspond the implementation of a given version of the class. In this way, the class developer may unilaterally change the implementation, hence the field, without breaking his/her commitment to maintain the interfaces.
Here is an example. Consider a class called Point. If you decide that a Point has x and y public attributes, then you may never change this. In contrast, if you have get/set X/Y methods, subsequent versions of the class may use various internal representations: rectangular coordinates (x, y), but also polar (r, theta), etc. All this without modifying the public interface.
A shorter version of your methods...
public void beDamaged(double damage) {
health = Math.max(0, health-damage);
}
public void gainHealth(double gainedHp) {
health = Math.min(maxHealth, health + gainedHp);
}
or even the following which can be called with +1 to gain, -1 to lose 1 hp.
public void adjustHealth(double adjustHp) {
health = Math.max(0, Math.min(maxHealth, health + adjustHp));
}
If you're not maintaining any invariants, then public fields are the way to go. If you do need an invariant across multiple members, then you need private fields and encapsulation.
But if you can't come up with any better names than GetFoo and SetFoo for the methods, it's a good clue that your getters and setters are probably worthless.
.... pathetic content omitted....
EDIT
sorry for beeing a little too pathetic -must be the pills... The other answers are quite relevant and good
One advantage not yet mentioned for avoiding public fields: if there aren't any public fields, one may define an interface that includes all the public features of the class, have the class implement that interface, and then have everyplace that uses the class use the interface instead. If that is done, one may later design a class which has completely different methods and fields, but which implements the same interface, and use that class interchangeably with the original. If this is done, it may be useful to have the class implement a static factory method in addition to the constructor, and have the factory return an object of the interface type. Doing that would allow later versions of the factory to return an object of some other type. For example, one may come up with a low-cost version of the object in which many properties return constants; the factory could see if such an object would be suitable, and if so return one instead of the normal object.
Incidentally, the concept of using a mixture of constant and mutable objects in an adventure goes back at least to 1980. In Warren Robinett's "Adventure" cartridge for the 2600, each object has a number of pointers stored in ROM for things like position and state, so objects which aren't going to move (such as the castle gates or the "signature") don't need to have their position stored in RAM, and most grabbable objects (which don't have any state other than their position) won't need to store a state in RAM, but animated objects like the dragons and bat can store both state and position in RAM. On a machine with 128 bytes of RAM total, such savings were critical.