An exploration of immutable types in java

An immutable class means that after an object instance of the class is created, the properties of the instance cannot be changed. The common String is the immutable class. The property values ​​of immutable types will not change, which is very useful in multi-threaded programming, without worrying about object property values ​​being modified.

Let's see how to implement an immutable type:

1. To ensure that the attribute value does not change, the attribute must be modified with private and final.

2. To initialize final properties in the constructor of the class, and only provide getter methods, not setter methods.

3. Rewrite equals and hashCode, and use the overridden equals method to judge whether two objects are equal according to the attribute value. The hashCode method ensures that different objects have different hashCodes.

Simplest immutable class implementation:

class Person
{
    private final String firstName;
    private final String lastName;
    public Person(String firstName,String lastName)
    {
        this.firstName=firstName;
        this.lastName=lastName;
    }
    public String getFirstName() 
    {
        return firstName;
    }
    public String getLastName() 
    {
        return lastName;
    }
    
    @Override
    public boolean equals(Object obj)
    {
        if(obj instanceof Person)
        {
            Person p=(Person)obj;
            return this.firstName.equals(p.firstName)&&this.lastName.equals(p.lastName);
        }else
        {
            throw new ClassCastException();
        }
    }
    @Override
    public int hashCode()
    {
        return (this.firstName+this.lastName).hashCode();
    }
}

The Person class is an immutable class. The properties are of private and final types, and only the getter method is provided, and the value of the property cannot be modified at all.

But if a class contains a mutable type it can not be so simple to achieve.

class Name
{
    private String firstName;
    private String lastName;
    public Name() {}
    public Name(String firstName, String lastName)
    {
        this.setFirstName(firstName);
        this.setLastName(lastName);
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName()
    {
        return lastName;
    }
    public void setLastName(String lastName)
    {
        this.lastName = lastName;
    }

}

class Person
{
    private final Name name;
    public Person(Name name)
    {
        this.name=name;
    }
    public Name getName() 
    {
        return name;
    }
    @Override
    public String toString()
    {
        return name.getFirstName()+"$"+name.getLastName();
    }    
}

The Person class contains a variable type Name. Although Name is modified by final and private, and only has a getter, the value of Name can still be modified:

        Person person=new Person(new Name("Hello","world"));
        System.out.println(person);
        person.getName().setFirstName("hel");
        System.out.println(person);

Output result:

Hello$world
hel $ world

Obviously, the purpose of an immutable class cannot be achieved. To become an immutable class, you need to return a new object in the getter and initialize it with the new object in the constructor:

    public Person(Name name)
    {
        this.name=new Name(name.getFirstName(),name.getLastName());
    }
    public Name getName() 
    {
        return new Name(name.getFirstName(),name.getLastName());
    }

This will not change the value of the object instance at all. The String class uses a similar implementation method, but uses a constant buffer pool, which greatly improves performance. Every time a String object is initialized, the constant buffer pool will be checked first, and if it already exists, a new constant string will not be created in memory.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324855682&siteId=291194637
Recommended