tags:

views:

125

answers:

7

Hello all. I was doing a project in a Java book and came across this code example. The author of the book said that instead of initializing X and Y in my constructor directly, I could call the class's setLocation() method instead. Unfortunately I do not have the book anymore for a concrete explanation on why this is better. I'm not too experienced with Java but isn't it just...simpler to assign values directly and not worry about another function call?

//Point constructor, normal way of initializing variables

private double x;
private double y;

Point(double initial_x, double initial_y)
{
 this.x = initial_x;   
 this.y = initial_y;
} 

//Point constructor, the other way

Point(double initial_x, double initial_y)
{ 
   setLocation(initial_x, initial_y);
} 


public void setLocation(double newX, double newY)
{
   this.x = newX;
   this.y = newY; 
}
+1  A: 

Because both instance vars are private in whichever example, the purpose of setLocation() in this context appears to be to allow other classes to modify the coordinates of the Point object, after it's been initialized. And since the constructor would have done effectively the same thing (again merely for this simple example), the constructor just calls that method for simplicity's sake.

BoltClock
A: 

You have more control as to when they are set.

Preet Sangha
+6  A: 

I would actually recommend against calling setters within a constructor, because calling overridable methods from within constructors is a bad idea. Also, the usual argument for getters/setters is that the logic may change, and you won't have to change everyone that accesses your properties. In this case, however, if the logic changes, the necessary changes are limited to the same class.

Adam Crume
rwong
Ok so if a class that extends Point is created and overrides setLocation() how is that bad? If the new class calls Point's constructor, wouldn't Point in turn call it's own setLocation() and avoid any bad behavior?
SDevil
I agree but question :) What if the logic beyond SetLocation did more than just set the properties AND needed to happen everytime the object was created?
Taylor
also thank you for the link @rwong
SDevil
+2  A: 

Same thing as everyone else said above, with an additional caveat:

I could see an argument against this practice if you were in need of immutable objects, for concurrency or other reasons. If you're doing anything where multiple threads might act on this object, the setter is probably going to get you in trouble.

Eric
A: 

If there is some logic involved in setting the members, and your class is mutable (providing a method which behaves like calling the constructor a second time) then it makes sense to use an initialization method.

private int width;
private int height;
private double diagonal;

Image(int initial_w, int initial_h)
{
 Init(initial_w, initial_h)
}

public void Init(int initial_w, initial_h)
{
 width = initial_w;
 height = initial.h
 diagonal = Math.sqrt(width*width + height*height); // constructor doesn't need to repeat this line
}
rwong
A: 

If x and y are mutable and have non-trivial setters, then using the setter to initialize them, even in the constructor, can help avoid duplication of code. In this case, you may wish to mark the setters as final to prevent the possibility of a derived class overriding these methods and causing your constructor to have unexpected behavior.

If the setters are trivial (simple assignment with no other code) then there's not much reason to use the setter in the constructor.

If the variables are immutable, it is far better to not have a setter at all and to initialize them directly in the constructor.

Eddie
If I want to stop a derived class from overriding a method can't I just declare it private?private void setLocation(){};
SDevil
@SDevil: Yes, but a private setter is not generally as useful as a public one. If you have a member variable that will be set exactly once by the constructor and never again, just make it final and set it directly in the constructor. This is a much better construction for several reasons.
Eddie
A: 

This resource may be of assistance:

http://en.wikipedia.org/wiki/JavaBean

I've personally found that having no-arg constructors simplifies dependency injection. For example with Spring IoC, while you can certainly specify constructor args, its a lot simpler not having to.

Also I've found that writing unit tests is simpler for the same reason i.e. you can just instantiate the object you want, inject the properties required for the purposes of your test and then test. Having a constructor with args may thus require you to set things up with an object that you're not particularly interested in testing.

That said, providing a no-arg constructor is not mutually exclusive to providing convenient constructors with args i.e. you can have both; just ensure that you have a no-arg one to meet the use-cases described above.

Christopher Hunt
Spring certainly has its problems. But what's the point of testing an invalid object? Perhaps the class is doing too much.
Tom Hawtin - tackline
Most DI frameworks are easier to set up with beans i.e. classes with no-arg constructors. I'm not sure that I understand your question, "But what's the point of testing an invalid object?". Please elaborate.
Christopher Hunt