美文网首页
[其他]不可变数据类型

[其他]不可变数据类型

作者: AlexLJS | 来源:发表于2019-03-02 23:00 被阅读0次

一、什么是不可变类

简言之,immutable, 创建完实例对象后,实例对象不可被改变。最典型的例子是String类。
String str = new String("hello");
str = "world";
System.out.println(str);
Out:world
看似这个对象被修改了,但实际上,是在内存中开辟了一个新空间。

注:在哪部分内存开辟了新空间?
学习String的时候,我们肯定被介绍过 常量池,知道String是个在底层存储是个final修饰的字符数组。我们的String被放在常量池中,如果新的字符串与之相同,新实例对象指向常量池。

        String str1 = new String("hello");
        String str2 = "hello";
        String str3 = "hello";
        System.out.println(str1 == str2);
        System.out.println(str2 == str3);
        System.out.println(System.identityHashCode(str1));
        System.out.println(System.identityHashCode(str2));
        System.out.println(System.identityHashCode(str3));

Out:
false
true
28014437
19451386
19451386

通过这段代码可以发现,使用new关键字创建的String并没有进入常量池,应该还是储存在堆内存空间中。所以上面问题,可能是在常量池也可能是在堆内存中开辟新空间,但新String肯定不是原内存地址,是不可变类。

二、创建一个不可变类

其实,我们可以创建一个不可变类,创建原则:

1、类的成员变量, final private修饰
2、构造器带参数,初始化成员变量
3、只提供getter方法,不提供setter方法
4、关于hashCode() 和equals() : 有必要的换进行重写,要根据成员变量的hash值进行equals 重写。

但是,这其中存在一个问题,如果一个不可变类中的某个成员变量是可变类的实例,那么这个不可变类,就变成了可变类。

public class Test {
    public static void main(String[] args) {
        Job job_1 = new Job("Student");
        Person person_1 = new Person("Alex",job_1);
        System.out.println(person_1);

        job_1.setJobName("Beggar");
        System.out.println(person_1);
    }
}
class Job{
    //可变
    private String jobName;
    public Job(){}
    public Job(String jobName){
        this.jobName = jobName;
    }

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    @Override
    public String toString() {
        return jobName ;
    }
}
class Person{
    //不可变
    private final String name;
    private final Job job;
    public Person(String name,Job job){
        this.name = name;
        this.job = job;
    }

    public String getName() {
        return name;
    }

    public Job getJob() {
        return job;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", job=" + job +
                '}';
    }
}

Out:
Person{name='Alex', job=Student}
Person{name='Alex', job=Beggar}

产生这个问题原因是,直接引用了一个可变对象,所以不可变了类中的可变成员变量都需要在类中new出来。
对构造器的修改如下:

public Person(String name,Job job){
        this.name = name;
        this.job = new Job(job.getJobName());
    }

三、缓存实例的不可变类

由于不可变实例不可被更改,所以相同的不可变实例要频繁开辟内存空间,这对系统资源是极大的消耗,所以我们要考虑缓存不可变实例。
注:当然盲目缓存,或者被缓存的对象使用频率很低会使得系统性能下降。
对Person修改如下:

public class Test {
    public static void main(String[] args) {
        Job job_1 = new Job("Student");
        //new 类似 new创建String
        //valueOf()相当于String s = "Student";类似于进入常量池
        Person person_1 = new Person("Alex",job_1);
        Person person_2 = new Person("Alex",job_1);
        Person person_3 = Person.valueOf("Alex",job_1);
        Person person_4 = Person.valueOf("Alex",job_1);
        System.out.println(person_1 == person_2);
        System.out.println(person_1 == person_3);
        System.out.println(person_3 == person_4);
    }
}
class Job{
    private String jobName;
    public Job(){}
    public Job(String jobName){
        this.jobName = jobName;
    }

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    @Override
    public String toString() {
        return jobName ;
    }

    @Override
    public boolean equals(Object o) {
        return o.toString().equals(jobName);
    }

}
class Person{
    //建立缓存,要在类之前加载static
    private static int MAX_SIZE = 10;
    private static Person[] cacheSpace = new Person[MAX_SIZE];
    private static int position = 0;

    private final String name;
    private final Job job;

    //构造器也可以隐藏
    public Person(String name, Job job){
        this.name = name;
        this.job = new Job(job.getJobName());
    }
    public static Person valueOf(String name , Job job){
        for(int i = 0 ; i < cacheSpace.length ; i++){
            if (cacheSpace[i] != null &&
                    (cacheSpace[i].getName().equals(name)&&cacheSpace[i].getJob().equals(job))){
                return cacheSpace[i];
            }
        }
        if (position == MAX_SIZE){
            cacheSpace[0] = new Person(name,job);
            position = 1;
        }else{
            cacheSpace[position++] = new Person(name ,job);
        }
        return cacheSpace[position - 1];
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(name, person.name) &&
                Objects.equals(job, person.job);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, job);
    }



    public String getName() {
        return name;
    }

    public Job getJob() {
        return job;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", job=" + job +
                '}';
    }
}
Out:
false
false
true

(参考了疯狂java讲义代码)

相关文章

  • [其他]不可变数据类型

    一、什么是不可变类 简言之,immutable, 创建完实例对象后,实例对象不可被改变。最典型的例子是String...

  • 快速理解Block

    调用block 调用block方式block名称(参数) 注意点:1、声明block属性时,不同于其他数据类型+变...

  • java基础篇二(数据类型)

    一、分类: 二、数据类型的转换: 自动类型转换: boolean类型不可能与其他任何数据类型进行转换,整数与浮点数...

  • JS里的数据类型转换及小技巧

    前言:之前的博客JS里的数据类型介绍了JS中的各种数据类型,那么可不可以把其他的数据类型转换成特定的一种数据类型呢...

  • JAVA的类型转换

    基本数据类型之间的转换(值转换) boolean类型不可以和其他基本数据类型进行转换 整型,字符型,浮点型之间的转...

  • 2018-06-10 JS 里的数据类型转换

    前言:之前的博客介绍了JS中的各种数据类型,那么可不可以把已经确定的数据类型转换成其他的数据类型呢?本文就将介绍一...

  • JS 里的数据类型转换

    将其他的数据类型转换为String 将其他的数据类型转换成Number 将其他的数据类型转换为Boolean 五个...

  • JS里的数据类型转换及小技巧

    前言:之前的博客你真的了解JS的数据类型?介绍了JS中的各种数据类型,那么可不可以把其他的数据类型转换成特定的一种...

  • JS里的数据类型转换及小技巧

    前言:之前的博客你真的了解JS的数据类型?介绍了JS中的各种数据类型,那么可不可以把其他的数据类型转换成特定的一种...

  • 2018-12-25(javascript基础笔记)

    数据类型转换 1.string 将一个数据类型强制转换为其他的数据类型 类型转换主要指,将其他数据类型,转为 st...

网友评论

      本文标题:[其他]不可变数据类型

      本文链接:https://www.haomeiwen.com/subject/aqyzeqtx.html