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

How to Create Immutable Class with List<String> Element in class

不可变 Class 与列表

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

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

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]

为什么以及如何将这个新的课程元素从客户端添加到列表中,因为它可以随时添加,所以我们如何解决这个问题,因为这个不可变的 class 应该不允许在创建后进行修改

阅读about immutableLists,您会发现不可变和不可修改是不一样的

我猜(根据你的问题)你期待一个你根本不创建的不可修改的列表...

请参阅 this answer 以获得正确的解决方案

this.courses = Collections.unmodifiableList(courses);

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

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

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

然后确保您的 getter 确实:

return Collections.unmodifiableList(courses);

使用 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"); 

在记忆方面不是最好的,但有效:


// 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 中)创建副本。