Using setter methods or direct reference to variable inside constructor? - java

Both methods work, however which is the proper way to do it?
Method one:
public class Object {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object(String name){
this.name = name;
}
}
Method two:
public class Object {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//Changed this.name = name to setName(name)
public Object(String name){
setName(name);
}
}
I've searched around but couldn't find an exact question that referred to this. If there is one, free to post the link and I'll remove the question

My first thought was to use the setter in the constructor. So if you want to change how the name is stored, or if you want to add any other behavior while setting the name, you just have to change it once.
But thinking just a bit more on this, I think using direct access to the variable is better if the class is not final and the method is not private. Otherwise someone could extend your, override the method, causing your constructor to call their method with unpredictable behavior.
Rule of thumb: If the class is not final, you should only call private methods in the constructor.

While using a setter in the constructor reduces code duplication, calling overrideable methods (ie non final / non private methods) in a constructor is discouraged - it can lead to weird bugs when extending a class.
Consider the following case (based off of your example):
public class Object {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//Changed this.name = name to setName(name)
public Object(String name){
setName(name);
}
}
With the following subclass:
public class SubObject extends Object {
private String Id;
#Override
public void setName(String name) {
super.setName(name + Id);
}
public SubObject(String name){
super(name);
this.id = "1";
}
}
Creating an instance of SubObject will cause a null pointer, as setName() is called in the constructor, but the implementation of setName() relies on the Id field having been initialized.
Someone extending a class should not have to go check the source code of the super class to ensure the constructor isn't calling overrideable methods.

If all the setter and constructor do is a simple assignment, it doesn't matter which of the two ways you choose.
However, if you need to perform some validations before assigning the new value to the member, it makes sense to have that logic in a single place, which means calling the setter method from the constructor is the better option.

I would NOT use the setter in the constructor. This because if someone added any other behavior while setting the name in the setter, I'd consider it a collateral effect.

If setName() coontains some inner logic about how the name should be set, then I would choose 2. On the other hand, if setName() contains some aditional code that needs to be run when name is set, i would choose 1.
Let me make a bit more complex situation so I can express my point:
class Person {
private String firstName;
private String lastName;
private boolean wasRenamed;
//getters...
public Person(String fullName) {
???
}
public void setFullName(String fullName) {
???
}
}
Here we have Persons with first and last names, also we want to keep record who was renamed and who not. Let's say fullName contains first and last name separated by space. Now let's look at 2 different approaches you provided in your question:
Not call setFullName() in costructor: This will lead to code duplicity (spliting fullName by space and assigning it to first and last name.
Do call setFullName() in costructor: This will add extra trouble with the wasRenamed flag, since setFullName() has to set this flag. (This could be solved by simply resetting the flag back to false in constructor after calling setFullName(), but let's say we don't want to do that)
So I would go with a combination of 1 and 2, and split the inner logic of setting the name and the additional code that needs to run before/after name is set into different methods:
class Person {
private String firstName;
private String lastName;
private boolean wasRenamed;
//getters...
private void setFullName0(String fullName) {
//split by space and set fields, don't touch wasRenamed flag
}
public Person(String fullName) {
setFullName0(fullName);
}
public void setFullName(String fullName) {
setFullName0(fullName);
wasRenamed = true;
}
}

Related

Why does a superclass reference calling an overridden method appear polymorphic, but not if it takes an overridden member variable?

package main.java;
public class Demo {
public static void main(String[] args) {
BClass bClass=new BClass("han","男");
AClass aClass=bClass;
System.out.println(aClass.getSex());
System.out.println(aClass.sex);
}
}
The execution result of this class is
男
null
The results are confusing to me. When the superclass calls the overridden method, the results meet my expectations, but when it calls the overridden variable, the results confuse me.so why does a superclass reference calling an overridden method appear polymorphic, but not if it takes an overridden member variable?Here's the entire code.
package main.java;
public class Demo {
public static void main(String[] args) {
BClass bClass=new BClass("han","男");
AClass aClass=bClass;
System.out.println(aClass.getSex());
System.out.println(aClass.sex);
}
}
package main.java;
public class AClass {
private String name;
public String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
package main.java;
public class BClass extends AClass{
private String sex;
public BClass(String name,String sex) {
this.sex = sex;
super.setName(name);
}
#Override
public String getSex() {
return sex;
}
#Override
public void setSex(String sex) {
this.sex = sex;
}
}
While you can override a method, you can't override a field in a subclass; you are actually just declaring a field with the same name. To allow the field to also be visible in the child class, you can change its visibility to protected or package private (default modifier), if both classes are in the same package. Demo.
public class BClass extends AClass{
public BClass(String name,String sex) {
this.sex = sex;
super.setName(name);
}
#Override
public String getSex() {
return sex;
}
#Override
public void setSex(String sex) {
this.sex = sex;
}
}
public class AClass {
protected String name, sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
Java doesn't allow you to really override a field.
Your BClass actually has two fields named sex, one from AClass, and one from BClass. And Java syntax doesn't really help you finding out which one is meant when you write something like x.sex. It's as if you had defined two different fields, sex_a in AClass and sex_b in BClass, only with the complication that references to both are written like x.sex, without a clear hint which of the two is meant here.
In your case:
Your BClass instance will have its sex_b initialized, and the sex_a empty (null).
aClass.getSex() always calls the most specific method, based on the instance's runtime class, being BClass. So it chooses the method from BClass, returning sex_b, and thus prints the sex.
aClass.sex accesses one of the two sex fields, depending on the variable's compile-time-deducible type, in your case being AClass. So it prints the sex_a value, being null.
Seasoned Java developers typically do their best to avoid this situation, as it can be very confusing.
If the two fields conceptually have the same meaning, do it as you did with the name field, having only one field in the parent class, and have the subclass access it via getters and setters (or by declaring protected visibility for the field).
If the two fields have conceptually different meanings (can an object have two different sexes?), use different names.
As per the Java specifications, the instance variables are not overridden from a super class by a sub class when it is extended.

why use setter in java if we can set all values using construtor? [duplicate]

This question already has answers here:
Setter methods or constructors
(10 answers)
Closed 3 years ago.
I have confusion about use of setter and constructor about value assigning. Why we use setter to set values independently if we can do it in a single constructor.
I have tried both methods using setter and construtor passing values and found no differnce. Need reasons for the differnece between them.
//setter
public class NegaE {
String name;
int id;
public void setname(String a){
this.name=a;
}
public void setid(int b){
this.id=b;
}
public String getname(){
return name;
}
public int getid(){
return id;
}
// now through constructor
public class NegaE {
String name;
int id;
public NegaE(String a,int b){
this.id=b;
this.name=a;
}
public String getname(){
return name;
}
public int getid(){
return id;
}
You only call a constructor once. If you set the values in the constructor, and don't have setters, a user can never change the initial value unless some other object method with private access does it.
Objects that have private final data members that are initialized in the constructor and no setters are called "immutable" == "unchanging".
This can be a very good thing. Immutable objects are thread safe; you can share them between threads without concern. It's a more functional style of programming.
If you have setters you can update the state directly as you wish. These are mutable objects. You have to be careful sharing these across threads. Mutable, shared data is not thread safe.
A constructor sets the initial values, but those values will need to have the ability the change over time because things change.
Setters and getters allow you to make rules and modify the data if needed.
Here's a real basic example to get the idea.
public String setName(String name){
if(name == null){
throw new InvalidNameException();
}
this.name = name;
}
public String getName(){
if(this.name == null){
return "No Name here";
}
return this.name;
}

Java overriding method Error

basically I created a Person class and a constructor which sets the name,last name,age of the Person.all the properties of the class were set the private as it should be. I have made setters and getters for all the properties. On the main method I tried to override one of the setters just for practice reason. Its did draw an error saying Person.name not visible which means it cannot access private, Why this is happening, I mean if wasn't overriding the method it would have access. but if I set it to protected mode i will work.
Here is the code:
class Person {
private int age;
private String name;
private String last_name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public Person(int age, String name, String last_name) {
this.age = age;
this.name = name;
this.last_name = last_name;
}
}
public class main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person per = new Person(15,"bb","Sb") {
public void setName(String name) {
this.name = "aaaa";
}
};
per.setName("asdfaf");
System.out.println(per.getName());
}
}
A private member is only accessible in the class in which it is declared.
You created an anonymous sub-class of Person and tried to access a private member of the super-class from the sub-class. This is never allowed.
When developers of a class wish to allow access to certain members of the class to its sub-classes, they set the acess level to protected.
You have created a class named Person and in the following lines you are trying to create an anonymous subclass:
Person per = new Person(15,"bb","Sb") {
public void setName(String name) {
this.name = "aaaa";
}
};
As mentioned in doc:
A subclass does not inherit the private members of its parent class
Here your anonymous subclass is trying to access private field name directly and so is the error. You can use getter/setter which are public. You can also check this related question on SO.
You cannot access private fields from outside your class, even if you are overriding it. You are basically defining a new subclass of Person in your main(), which isn't allowed access to the private field Person.name. However, it can access a protected field.
Basic idea behind overriding is to redefine existing functionality and give new definition to it. If you refer to documentation, private member variables are only accessible in it own class. That why it is not available in your anonymous sub-class implementation.
Note: Generally we do not override setter methods as they are not a functionality.
This is called encapsulation . You can not access private vars from other classes . you can find more description here

Setter params final in Java

I have always been programming in java, and recently i started learning some c++.
In C++ it is conventional to set setter params as const, why don't we see this as much in java ?
I mean are there any disadvantages to creating a setter like so:
public void setObject(final Object o){ this.o=o; }
vs
public void setObject(Object o){ this.o=o; }
The first one should enforce for Object param o to stay constant through the whole set function, not ?
Edit:
A final param would enforce this NOT to happen :
public void setName(String name){
name="Carlos";
this.name=name;
}
The user will never be able to set the name different from "Carlos"
There's little advantage to setting a Java method parameter as final since it does not stop someone from changing the parameter reference's state within the method. All it prevents is the re-assignment of the parameter variable to something else, which does nothing to the original reference, and it allows for use of the parameter in anonymous inner classes. If you wanted true safety in this situation, you'd strive to make your parameter types immutable if possible.
Edit
You've posted:
public void setObject(Object o){
o++; // this does not compile
this.o=o;
}
Which mixes primitive numeric and reference type. It only makes sense if o is an Integer or other numeric wrapper class, and even so, making it final would not prevent someone from creating:
private void setI(final Integer i) {
this.i = 1 + i;
}
But neither your code nor this code above would affect the parameter object on the calling code side.
Edit
OK now you've posted:
public void setName(String name){
name="Carlos";
this.name=name;
}
But then someone could write
public void setName(final String name){
this.name= name + " Carlos";
}
Here's where the danger comes and where final doesn't help. Say you have a class called Name:
public class Name {
private String lastName;
private String firstName;
public Name(String lastName, String firstName) {
this.lastName = lastName;
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
And then a class, Foo, with a Name field and a setter. This is dangerous code:
class Foo {
private Name name;
public void setName(final Name name) {
name.setFirstName("Carlos");
this.name = name;
}
}
Because not only does it change the state of the field, it changes the state of the Name reference in the calling code, and the final modifier won't help one bit. The solution: make Name immutable.
e.g.,
import java.util.Date;
// class should be declared final
public final class BetterName {
private String lastName;
private String firstName;
private Date dateOfBirth;
public BetterName(String lastName, String firstName, Date dob) {
this.lastName = lastName;
this.firstName = firstName;
// make and store a private copy of non-immutable reference types
dateOfBirth = new Date(dob.getTime());
}
// only getters -- no setters
public String getLastName() {
return lastName;
}
public String getFirstName() {
return firstName;
}
public Date getDateOfBirth() {
// return copies of non-immutable fields
return new Date(dateOfBirth.getTime());
}
}
Okay, a final parameter/variable cannot be assigned to. As the java compiler needs to be capable to determine if a variable/parameter is actually final (for anonymous inner classes), optimization is no factor AFAIK.
It is more that C++ has a larger tool set, which java tried to reduce. Hence using C++ const string& is important, saying
The string is passed by pointer, access is automatically dereferenced.
If the actual argument is a variable, the variable itself is not changed.
Mind there might be a conversion operator for passing something else than a const string&.
Now java:
Java does not allocate objects on the stack, only keeps primitive types and object handles on the stack.
Java has not output parameters: a variable passed to a method call will never change its immediate value.
Back to your question:
As a setter in java mostly would not benefit from a final parameter.
A final will be a contract to not use the variable for a second assignment.
However:
public final void setXyz(Xz xyz) {
this.xyz = xyz;
}
is more useful: this method cannot be overriden, and hence may be safely used in a constructor. (Calling an overriden method in a constructor would be in a context of a still not initialized child instance.)

Java: Adding fields and methods to existing Class?

Is there, in Java, a way to add some fields and methods to an existing class?
What I want is that I have a class imported to my code, and I need to add some fields, derived from the existing fields, and their returning methods.
Is there any way to do this?
You can create a class that extends the one you wish to add functionality to:
public class sub extends Original{
...
}
To access any of the private variables in the superclass, if there aren't getter methods, you can change them from "private" to "protected" and be able to reference them normally.
Hope that helps!
You can extend classes in Java. For Example:
public class A {
private String name;
public A(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
public class B extends A {
private String title;
public B(String name, String title){
super(name); //calls the constructor in the parent class to initialize the name
this.title= title;
}
public String getTitle(){
return this.title;
}
public void setTitle(String title) {
this.title= title;
}
}
Now instances of B can access the public fields in A:
B b = new B("Test");
String name = b.getName();
String title = b.getTitle();
For more detailed tutorial take a look at Inheritance (The Java Tutorials > Learning the Java Language > Interfaces and Inheritance).
Edit: If class A has a constructor like:
public A (String name, String name2){
this.name = name;
this.name2 = name2;
}
then in class B you have:
public B(String name, String name2, String title){
super(name, name2); //calls the constructor in the A
this.title= title;
}
The examples only really apply if the class you're extending isn't final. For example, you cannot extend java.lang.String using this method. There are however other ways, such as using byte code injection using CGLIB, ASM or AOP.
Assuming this question is asking about the equivalent of C# extension methods or JavaScript prototypes then technically it is possible as this one thing that Groovy does a lot. Groovy compiles Java and can extend any Java class, even final ones. Groovy has metaClass to add properties and methods (prototypes) such as:
// Define new extension method
String.metaClass.goForIt = { return "hello ${delegate}" }
// Call it on a String
"Paul".goForIt() // returns "hello Paul"
// Create new property
String.metaClass.num = 123
// Use it - clever even on constants
"Paul".num // returns 123
"Paul".num = 999 // sets to 999
"fred".num // returns 123
I could explain how to do the same way as Groovy does, but maybe that would be too much for the poster. If they like, I can research and explain.

Categories