Home > Blockchain >  Final attribute vs. a Private attribute with no Setter method in Java
Final attribute vs. a Private attribute with no Setter method in Java

Time:05-17

In Java, I feel that using Private when declaring an attribute and not declaring a Setter method for it gives the same outcome as using Final when declaring the attribute, both allow the variable to stay constant.

If that is the case, what is the benefit of using Final in this scenario?

CodePudding user response:

Even without a setter other methods in the class can change the attribute so it's a completely different concept. Many would argue it's not a good thing to do (it adds "side effects" to your program) but it's still possible.

CodePudding user response:

The answer is Encapsulation

Consider this.

public class Point
{

    int x, y;

    public Point(int x, int y)
    {

        this.x = x;
        this.y = y;

    }

    //no getters or setters needed, I can just modify or read x and y directly.

}
public class FinalPoint
{

    public final Point point;

    public FinalPoint(int x, int y)
    {

        this.point = new Point(x, y);

    }

    //no getters needed, I'll just read point since it is public

}

Right now, this FinalPoint has a final Point as an instance field. On the one hand, it means that that instance field cannot be reassigned. However, the fields of that instance field can definitely be reassigned.

For example.

FinalPoint p = new FinalPoint(1, 2);
p.point.x = 4; //I have now modified state! final did not protect us here

The final keyword is powerful, but it does not mean that your data is unchangeable. It only means that that surface level reference is unchangeable - it will force a reference to always point to the same object. That does not stop the object its pointing to from changing it's internal state as much as it wants. The only guarantee final makes is that you always be pointing at the same object.

Which brings us to encapsulation. Encapsulation was created to solve this exact problem and more.

Consider this.

public class EncapsulatedPoint
{

    private Point point;

    public EncapsulatedPoint(int x, int y)
    {

        this.point = new Point(x, y);

    }

    public int getX() { return this.point.x; }
    public int getY() { return this.point.y; }

}

Now, because I have encapsulated Point and exposed only the data I can safely expose, I have protected myself from modification. It is impossible to change this object (without using reflection or other hacks the designers are actively removing). It truly is Immutable.

Of course, Encapsulation is not superior to using final. There is a time and a place for both. Knowing when and where allows you to make your software secure.

CodePudding user response:

Private variables will never access from the outside of the class and Final will never change by taking input from the user.

CodePudding user response:

Assumed you are talking about variables, the keywords final and private define different characteristics.

The keyword final denies any changes to the variable and throws compilation errors when modified or changed. However, without specifying public or private, with the default package-private access modifier, it could be accessed by other classes in the same package once initialized (text with bold fonts are corrected by @charsofire and @MC Emperor).

On the other hand, the keyword private rejects the idea of being called by other classes, even in the same package. But it could be changed and modified by methods in the same class, even without setter or getter methods.

For example in the same class of the same package:

public class Student {
    private int score;

    final int id;

    public Student(int id, int score) {
        this.id = id;
        this.score = score;
    }

    public void modifyGrade(int newScore) {
        // Accepted
        this.score  = newScore;
    }

    public void modifyID(int id) {
        // Rejected
        this.id = id;
    }
}

And in different class of the same package:

public class School {

    public static void main(String[] args) {
        Student student = new Student(0, 35);
        
        // Accepted
        System.out.println(student.id);
        // Rejected
        System.out.println(student.score);

        // Accepted
        student.modifyGrade(29);
        
        // throws exception
        student.id = 5;
        // Not visible
        student.score = 29;
    }    
}

Hope this answer helps you well,

and many thanks again to both @charsofire and @MC Emperor, who helped to clarify significantly in this answer.

  • Related