-4

what is the reason of String class to make "public class final String ". below I have written an immutable class without the final keyword. could anyone can able to break this class immutability.

mport java.util.Date;

public class Person {

    private final String name;
    private final Date dob;

    public Person(String name, Date dob) {
        this.name = name;
        this.dob = dob;
    }

    public String getName() {
        System.out.println("in person :" + name);
        return this.name;
    }

    public Date getDob() {
        System.out.println("in person :" + dob);
        return this.dob;
    }

}
rimonmostafiz
  • 1,341
  • 1
  • 15
  • 33
Bharat
  • 7
  • 5
  • 1
    I can subclass it and add another field that has a setter. – Sweeper Jan 17 '18 at 06:34
  • The code formatting is wrong. Please write your question as plain text before the code. – Roland Weber Jan 17 '18 at 06:35
  • I want to know the reason how will break the immutability of above code if we are not using final keyword with the class name. – Bharat Jan 17 '18 at 06:37
  • 1
    It's funny that you call your class "immutable" although it provides access to mutable fields. – Tom Jan 17 '18 at 07:02
  • 1
    Possible duplicate of [Why would one declare an immutable class final in Java?](https://stackoverflow.com/questions/12306651/why-would-one-declare-an-immutable-class-final-in-java) – Tom Jan 17 '18 at 08:09

3 Answers3

4

You haven't written a immutable class because the final modifier for the class is missing.
Or you need a final modifier for the methods getName() and getDob() so that this fields are immutable.

In your example it's still possible to "modify" the class with a subclass. For example:

public class EditablePerson extends Person {
    // create new fields for name and dob
    // this is possible because the private fields of the superclass are not visible
    private String name;
    private Date  dob;

    public EditablePerson(String name,Date dob){
        // call the constructor of the super-class with dummy-data
        super("garbage", null);
        this.name=name;
        this.dob=dob;
    }

    @Override
    public String getName(){
        System.out.println("in person :"+name);
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }


    @Override
    public Date getDob(){
        System.out.println("in person :"+dob);
        return this.dob;
    }

    public void setDob(Date dob) {
        this.dob = dob;
    }
}

To test this:

Person p=new EditablePerson("P", new Date());
p.getName();
if(p instanceof EditablePerson) {
    ((EditablePerson)p).setName("Changed");
}
p.getName();

As @Tom noted:

The class Person is also not immutable because it has a field with a mutable class (the class Date is mutable) which can be changed from the outside.

Here the example:

Person p=new Person("P",new Date());
p.getDob();
p.getDob().setTime(0l);
p.getDob()

Also read: A Strategy for Defining Immutable Objects

  • You don't need a subclass to modify the data. – Tom Jan 17 '18 at 07:00
  • I am adding some output of your code and enable to see the how my class object changing . – Bharat Jan 17 '18 at 07:02
  • @Tom Sure you do. You can't modify the data in `Person`, since the fields are `final`. – Andreas Jan 17 '18 at 07:02
  • Person p=new Person("P",new Date()); p.getName(); EditablePerson ed=new EditablePerson("E", new Date()); ed.getName(); p.getName(); ed.setName("Setting new One"); ed.getName(); p.getName(); Person p2=new EditablePerson("Child Object", new Date()); p2.getName(); ed.getName(); p.getName(); – Bharat Jan 17 '18 at 07:02
  • in person :P in person :E in person :P in person :Setting new One in person :P in person :Child Object in person :Setting new One in person :P – Bharat Jan 17 '18 at 07:03
  • 1
    @Andreas Come on, you should be experienced enough to know that `Date` is mutable and it very well can be mutated by using the instance passed by `getDob`. – Tom Jan 17 '18 at 07:05
  • @Bharat I add the proper testcode to prove that person is not immutable. –  Jan 17 '18 at 07:07
  • @Tom If you want to cover the fallibility of `Date` being mutable, though almost everything uses it as-if it was immutable, then say so. That is a problem with `Date`, easily fixed by using `LocalDate` instead, and has nothing to do with the discussion about whether the lack of `final` makes the class mutable. Even adding `final` wouldn't fix the `Date` problem. – Andreas Jan 17 '18 at 07:11
  • Making getter `final` doesn't make `Person` immutable either. @Tom is right that without subclassing `Person` is already technically mutable because `Date` field is not immutable. – Jai Jan 17 '18 at 07:12
  • @Andreas The whole premise of OP "I build an immutable class" is already wrong and not worth to further discuss since he doesn't seem to have the basic understanding of what he's doing anyway. – Tom Jan 17 '18 at 07:17
  • @Tom I read the question more like "is this class really immutable", and therefore we can show the OP all the mistakes which makes the class not immutable. –  Jan 17 '18 at 07:22
  • 1
    @devpuh Or we understand that this question has been asked several times before (here and on software engineering) and close this as a dupe. – Tom Jan 17 '18 at 08:10
0

A class that is declared final cannot be used as a base class. Nobody can add attributes or methods to it. See also Use of final class in Java

Roland Weber
  • 1,865
  • 2
  • 17
  • 27
0
public class MutablePerson extends Person {

    private Gender gender;
    public MutablePerson(String name,Date dob, Gender gender) {
        super(name, dob);
        this.gender = gender;
    }

    public final Gender getGender() { return gender; }
    public final void setGender(Gender g) { gender = g; }

    // Override hashcodes and equals as required.
}

public Person getPerson() { return new MutablePerson("Richard", new Date(), Gender.MALE); }

Person person = getPerson(); // Cannot assume person is immutable.

There you go, this is no longer immutable.

Jai
  • 8,165
  • 2
  • 21
  • 52
  • 1
    `MutablePerson` is not immutable, that is true, but anyone using the object as a `Person` will see it as immutable, because nothing they can see will ever change. This is a bad example. [Answer by devpuh](https://stackoverflow.com/a/48295117/5221149) shows how overriding the base class methods actually make the `Person` object appear mutable too. – Andreas Jan 17 '18 at 06:51
  • @Andreas Anyone is free to cast it and manipulate it, and no exceptions will be thrown. When you assume that this is immutable because you see it is `Person` type, you are going to get mysterious symptoms later on (e.g. using that instance as a key of a hashmap). – Jai Jan 17 '18 at 06:54
  • You're right, *if* subclass overrides `hashCode` and `equals`. Your code doesn't. Still bad example. As subclass currently is written, anyone using the `MutablePerson` as a `Person` will never see any changes to the object, even if used as a key in a `HashMap`. – Andreas Jan 17 '18 at 07:04
  • @Andreas I did say override hashcode and equals. I'm just lazy to write concrete implementation in the example. – Jai Jan 17 '18 at 07:13
  • If your point was that override `hashCode` and `equals` would make `Person` appear mutable, then you should have said so, and shown by writing them, and the `gender` stuff is then unnecessary, because it doesn't have anything to do with that. Your answer is all about `gender`, but that doesn't make the point you're trying to make. Still bad example. – Andreas Jan 17 '18 at 07:22
  • https://fliprank.blogspot.com/2018/12/webtraffic-management-load-balancer.html?m=0 – Bharat Dec 27 '18 at 20:18