如何创建一个具有List<String>元素的不可变类

3

使用List实现不可变类

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]

为什么以及如何将这个新的Course元素添加到列表中,因为它来自客户端,所以随时都可以添加,那么我们如何解决这个问题,因为这个不可变类创建后不应该允许修改。

2
在设置时克隆列表。 - Scary Wombat
2
我总是把它们搞混 - 所以你的问题非常合理 +1 - Martin Frank
4个回答

4

this.courses = Collections.unmodifiableList(courses);

这将创建一个名为"unmodifiable"的不可修改列表。但这只是对原始列表的一个视图。因此对于那个原始列表的更改将在您的“不可修改”的视图中可见。

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

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

然后确保您的getter执行以下操作:

return Collections.unmodifiableList(courses);

是的 - 它必须是不可修改的 - 而不是不可变的 ^_^ +1 - Martin Frank
1
this.courses = Collections.unmodifiableList(new ArrayList<>(courses)); 这段代码也足够了。 - Lothar
谢谢@GhostCat,你的方法也可以,但Koziolek的方法也可以,哪个更好、更合适呢? - Sadina Khatun

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


在构造函数中输入时,您会创建列表副本;在获取器中输出时,您也会创建副本。

谢谢@Koziolek,你的方法也可以,但GhostCat也可以,哪个更好、更合适呢? - Sadina Khatun

1

阅读关于ImmutableLists的内容,你会发现Immutable和Unmodifiable并不是一样的

我猜测(从你的问题中),你希望有一个不可修改的列表,但你并没有创建它...

请查看这个答案以获得正确的解决方案。


0
使用 Collections.unmodifiableList,它会创建一个包装器来包装原始列表,并且该包装器对象是不可修改的。原始列表仍然可以被更新。
因此,为了使 List<String> courses 列表不可变,您可以使用 Apache collection common 库。 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"); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接