如何在类中使用List <String>元素创建不可变的类

时间:2019-10-21 07:58:54

标签: java arraylist immutability immutable-collections

具有列表的不可变类

package com.text.immutable;

import java.util.Collections;
import java.util.List;

// An immutable class Student
public final class Student 
{ 
    final String name; 
    final int regNo; 
    final List<String> courses;  // want to make Immutable 

    public Student(String name, int regNo, List<String> courses) 
    { 
        this.name = name; 
        this.regNo = regNo; 
        this.courses = Collections.unmodifiableList(courses);
    } 
    public String getName() 
    { 
        return name; 
    } 
    public int getRegNo() 
    { 
        return regNo; 
    } 

    public List<String> getCourses() {
        return courses;
    }
} 

测试不可变类以打破不可变性

package com.text.immutable;

import java.util.ArrayList;
import java.util.List;

class ImmutablityTest 
{ 
    public static void main(String args[]) 
    { 
        List<String> courses = new ArrayList<String>();
        courses.add("java");
        courses.add("spring");
        courses.add("hibernate");
        courses.add("rest");

        Student s = new Student("ABC", 101, courses); 

        System.out.println("Before Update List");
        System.out.println(s.getName()); 
        System.out.println(s.getRegNo()); 
        System.out.println(s.getCourses());
        courses.add("Hibernate"); // Able to Change which affect final OutCome
        //s.getCourses().add("SpringBoot"); // giving Exception in thread "main" java.lang.UnsupportedOperationException

        System.out.println("After Update List");
        System.out.println(s.getName()); 
        System.out.println(s.getRegNo()); 
        System.out.println(s.getCourses());

    } 
} 

输出为

Before Update List
ABC
101
[java, spring, hibernate, rest]
After Update List
ABC
101
[java, spring, hibernate, rest, Hibernate]

为什么以及如何可以随时添加从客户端添加到列表中的新课程元素,因此我们如何解决此问题,因为一旦创建后,该不变类将不允许修改

4 个答案:

答案 0 :(得分:4)

  

this.courses = Collections.unmodifiableList(courses);

顾名思义,这将创建一个不可修改列表。但这只是原始列表上的视图。因此,对该原始列表的更改在“不可修改”视图中可见。

如有疑问,请克隆您的列表,例如:

this.courses = new ArrayList<>(courses);

然后确保您的 getter 可以做到:

return Collections.unmodifiableList(courses);

答案 1 :(得分:2)

不是最佳的内存环境,但是可以:


// An immutable class Student
public final class Student 
{ 
    final String name; 
    final int regNo; 
    final List<String> courses;  // want to make Immutable 

    public Student(String name, int regNo, List<String> courses) 
    { 
        this.name = name; 
        this.regNo = regNo; 
        this.courses = new ArrayList(courses);
    } 
    public String getName() 
    { 
        return name; 
    } 
    public int getRegNo() 
    { 
        return regNo; 
    } 

    public List<String> getCourses() {
        return new ArrayList(courses);
    }
} 

在输入时(在构造函数中)创建列表的副本,在输出时(在getter中)创建副本。

答案 2 :(得分:1)

阅读about immutableLists,您会发现不可修改和不可修改

我猜(根据您的问题),您期望的是一个不可修改的列表,而您根本不会创建...

请参阅this answer以获取适当的解决方案

答案 3 :(得分:0)

使用Collections.unmodifiableList,它围绕原始列表创建一个包装器,并且该包装器对象不可修改。原始列表仍然可以更新。

因此,为了使List<String> courses列表不可变,可以使用Apache集合公共库。

List<String> immutableList = com.google.common.collect.ImmutableList.of("Geeks", "For","Geeks");

ImmutableList已覆盖List.add方法,始终抛出异常java.lang.UnsupportedOperationException


第二种方法是在构造函数本身内部创建列表。

public Student(String name, int regNo,  String... args) 
{ 
    this.name = name; 
    this.regNo = regNo; 
    courses = (List)Arrays.asList(args);

}

并这样称呼它:

 Student s = new Student("ABC", 101, "a","a","a","a");