java中的不可变类型的探究

Posted yq-blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中的不可变类型的探究相关的知识,希望对你有一定的参考价值。

不可变类是指创建类的对象实例后,该实例的属性不能发生改变。常见的String就是不可变类。不可变类型的属性值不会发生改变,这在多线程编程的时候非常有用,不用担心对象的属性值被修改。

下面我们来看看如何实现一个不可变类型:

1.要保证属性值不发生改变,属性必须用private和final修饰。

2.要在类的构造函数中初始化final属性,并且只提供getter方法,不提供setter方法。

3.重写equals和hashCode,使用重写的equals方法根据属性值判断两个对象是否相等,hashCode方法保证不同的对象,hashCode不同。

最简单的不可变类实现方法:

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();
    }
}

Person类就是一个不可变类,属性都是private和final类型,并且只提供了getter方法,根本无法修改属性的值。

但是如果一个类中包含了一个可变类型那就不能这么简单的实现了。

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();
    }    
}

Person类中含有一个可变类型Name,虽然Name被final和private修饰,并且只有getter,但是仍然可以修改Name的值:

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

输出结果:

Hello$world
hel$world

很明显不能达到不可变类的目的,要想变成不可变类,需要在getter中返回一个新的对象,在构造器中也要用新的对象初始化:

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

这样就完全不会改变对象实例的值了。String类就是使用了类似的实现方法,不过使用的常量缓存池,大大提高了性能。每次初始化String对象是都会先检查常量缓存池,如果已经存在则不会再内存中创建新的常量字符串了。

 


以上是关于java中的不可变类型的探究的主要内容,如果未能解决你的问题,请参考以下文章

接口,泛型,可变参数在代码向上抽去中的应用探究

python中的不可变类型和可变类型

python类中的不可变属性和类型检查

Java中的不可变数组

java中的不可变类

关于Java中的String类的不可变