天道酬勤,学无止境

My Face class does not seem to be immutable even though I already declared it as final, how do I correct it?

I am trying to make my Face class immutable such that my Face object will not change once it has been initialized. This is what I have so far:

public class Face{
  protected final int[][] grid;
  protected Face half;

  public Face(int[][] grid){
    this.grid = grid;
  }


  public Face rotateRight(){
    int rows = 3;
    int cols = 3;
    int[][] transposedArray = new int[3][3];

    for (int i = 0; i<rows; i++){
      for (int j = 0; j<cols; j++){
        transposedArray[i][j]=grid[rows-j-1][i];
      }
    }

    return new Face(transposedArray);
  }

  public Face rotateLeft(){
    int rows = 3;
    int cols = 3;
    int[][] transposedArray = new int[3][3];

    for (int i = 0; i < 3; i++){
      for (int j = 0; j < 3; j++){
        transposedArray[2-j][i] = grid[i][j];
      }
    }
    return new Face(transposedArray);
  }

  public Face rotateHalf(){
    half = this.rotateRight();
    half = half.rotateRight();
    return half;
  }

  public int[][] getGrid(){
    return (this.grid).clone();
    }

  public String toString(){
    String str = "";
    for (int i = 0; i<3;i++){
      for (int j = 0; j<3; j++){
        str += String.format("%02d",grid[i][j]);
      }
    }
    String str1 = str.substring(0,6);
    String str2 = str.substring(6,12);
    String str3 = str.substring(12,18);
    return str1+"\n"+str2+"\n"+str3;
  }
}

However, when I try to run the following:

int[][] g = f.getGrid();
g[1][1] = 9;

I expect f to remain as

010203
040507
070809

but I end up getting

010203
040906
070809

instead. Is my Face object not made immutable even though I have already declared the class as final?

评论

You need to make a defensive copy of the input grid in the constructor.

Also, the fields should be private as well, and the class should be final too, although I suspect those last two points are not the cause of your problem.

Not tested:

  public Face(int[][] grid){
    int temp[][] = new int[ grid.length ][];
    for( int i = 0; i < temp.length; i++ ) 
      temp[i] = Arrays.copyOf( grid[i], grid[i].length );
    this.grid = temp;
  }

Your problem could be that your constructor doesn't clone the incoming array. So maybe the code that creates the Face class instance later manipulates the array it passed to the new Face object!

Unfortunately, there is no way to create truly immutable arrays in the Java. Declaring an array as final only prevents you from changing the array as a whole, it is still possible to change individual rows, columns, slots in that array.

If you want immutable collections, you need to turn actual Collection classes and then use the methods within the Collections class to create unmodifiable views over them.

Be careful when using clone.

On arrays, it does a shallow copy. The following snippet explains it better:

int[] c0 = new int[]{1, 2, 3};
int[] c1 = new int[]{4, 5, 6};
int[] c2 = new int[]{7, 8, 9};
int[][] grid = new int[][]{c0, c1, c2};
int[][] cloned = grid.clone();

assert cloned[0] == c0;
assert cloned[1] == c1;
assert cloned[2] == c2;

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • Scala:var List 与 val MutableList(Scala: var List vs val MutableList)
    问题 在 Odersky 等人的 Scala 书中,他们说使用列表。 我还没有完整地阅读这本书,但所有示例似乎都使用了 val List。 据我了解,也鼓励在 vars 上使用 vals。 但是在大多数应用程序中,在使用 var List 还是 val MutableList 之间没有权衡吗? 显然,我们尽可能使用 val List。 但是使用大量 var 列表(或 var 向量等)是一种好习惯吗? 我对来自 C# 的 Scala 很陌生。 在那里我有很多: public List<T> myList {get; private set;} 如果 C# 具有内置的不变性,则可以很容易地将集合声明为 val,因为集合本身在构造后永远不会改变,即使元素会在其生命周期中从集合中添加和减去。 因此,声明一个 var 集合几乎感觉就像是远离不变性的一步。 作为对回答和评论的回应,Scala 的一大卖点是:它可以有很多好处,而不必像 Lisp 或 Haskell 那样完全改变编写代码的方式。 回答1 使用大量 var 列表(或 var 向量等)是一种好习惯吗? 我会说将var与不可变集合一起使用比将val与可变集合一起使用更好。 离开我的头顶,因为 你对行为有更多的保证:如果你的对象有一个可变列表,你永远不知道其他外部对象是否会更新它您限制了可变性的范围; 返回集合的方法将产生一个不可变的集合
  • 即使更冗长,在foreach之外定义变量是否是更好的编码实践?(Is it better coding practice to define variables outside a foreach even though more verbose?)
    问题 在以下示例中: 第一个似乎比较冗长,但资源浪费较少第二个则不太冗长,但更浪费资源(重新定义每个循环的字符串) 哪种编码方法更好? 第一个例子: using System; using System.Collections.Generic; namespace TestForeach23434 { class Program { static void Main(string[] args) { List<string> names = new List<string> { "one", "two", "two", "three", "four", "four" }; string test1 = ""; string test2 = ""; string test3 = ""; foreach (var name in names) { test1 = name + "1"; test2 = name + "2"; test3 = name + "3"; Console.WriteLine("{0}, {1}, {2}", test1, test2, test3); } Console.ReadLine(); } } } 第二个例子: using System; using System.Collections.Generic; namespace
  • 从多个线程(不做任何修改)从java.util.HashMap获取值是否安全?(Is it safe to get values from a java.util.HashMap from multiple threads (no modification)?)
    问题 在某些情况下,将构造一个映射,并且一旦对其进行初始化,就永远不会再对其进行修改。 但是,它将从多个线程访问(仅通过get(key))。 以这种方式使用java.util.HashMap是否安全? (当前,我很高兴地使用java.util.concurrent.ConcurrentHashMap ,并且没有提高性能的必要性,但是只是想知道一个简单的HashMap是否足够。因此,这个问题不是“我应该使用哪个? “也不是性能问题。相反,问题是“安全吗?”) 回答1 当且仅当对HashMap的引用已安全发布时,您的惯用法才是安全的。 安全发布不会处理HashMap本身内部的任何问题,而是处理构造线程如何使对地图的引用对其他线程可见。 基本上,这里唯一可能的竞赛是在HashMap的构造和在完全构造HashMap之前可以访问它的任何读取线程之间进行的竞争。 大多数讨论都是关于map对象的状态发生了什么,但这是无关紧要的,因为您从未修改过它-因此,唯一有趣的部分是如何发布HashMap参考。 例如,假设您像这样发布地图: class SomeClass { public static HashMap<Object, Object> MAP; public synchronized static setMap(HashMap<Object, Object> m) { MAP = m; } }
  • Objective-C 中的不可变对象:大 init 方法?(Immutable Object in Objective-C: Big init method?)
    问题 我想在 Objective-C 中有一个具有不可变字段的对象。 在 C# 中,我会使用带有私有 setter 和大构造函数的属性。 我会在 Objective-C 中使用什么? 使用@property 似乎不允许我将 setter 声明为私有。 使用 initWithData: (NSString*) something createDate: (NSDate*) date userID: (long) uid 如果我要设置的属性超过 4 个,则似乎过于冗长。 我会在 .h 文件中声明 getter 而只在 .m 中声明 setter 吗? 我需要在某些内容和日期上使用保留或复制(顺便说一句:我应该使用这两个中的哪一个?),所以我需要在 setter 中使用一些代码。 或者还有其他类似不可变关键字的东西吗? 回答1 您可以拥有一个公共只读属性,并在您确实需要时使用私有读写属性为类中的属性提供一个 setter。 但是,您应该考虑是否有必要。 例如,考虑以下不可变 Person 类的声明和定义: // Person.h #import <Foundation/Foundation.h> @interface Person : NSObject { @private NSString *name_; NSDate *dateOfBirth_; } @property
  • 我可以在向量中使用const来允许添加元素,但不能对已添加的元素进行修改吗?(Can I use const in vectors to allow adding elements, but not modifications to the already added?)
    问题 我对这个答案的评论让我思考了常数和排序的问题。 我玩了一下,将我的问题简化为以下代码: #include <vector> int main() { std::vector <const int> v; } 将无法编译-您无法创建const ints向量。 显然,我应该知道这一点(理智上我也知道),但是我从来不需要创建这样的东西。 但是,这对我来说似乎是一个有用的构造,并且我想知道是否有任何办法可以解决此问题-我想将内容添加到矢量(或其他任何内容)中,但是一旦添加它们就不应更改。 可能有一些令人尴尬的简单解决方案,但这是我以前从未考虑过的事情。 我可能不应该提到排序(我可能会问另一个问题,请参阅这里以提出问题的难度)。 我真正的基本用例是这样的: vector <const int> v; // ok (i.e. I want it to be OK) v.push_back( 42 ); // ok int n = v[0]; // ok v[0] = 1; // not allowed 回答1 好吧,在C ++ 0x中,您可以... 在C ++ 03中,有一个段落23.1 [lib.containers.requirements] / 3,其中说 存储在这些组件中的对象的类型必须满足CopyConstructible类型(20.1.3
  • 不变性和重新排序(Immutability and reordering)
    问题 出于明显的原因,以下代码(实践中的Java Concurrency清单16.3)不是线程安全的: public class UnsafeLazyInitialization { private static Resource resource; public static Resource getInstance() { if (resource == null) resource = new Resource(); // unsafe publication return resource; } } 但是,在几页之后的16.3节中,它们指出: 如果Resource是不可变的,则UnsafeLazyInitialization实际上是安全的。 我不明白那句话: 如果Resource是不可变的,则任何观察resource变量的线程都将看到它为null或已完全构建(由于Java Memory Model提供了对最终字段的强有力保证) 但是,没有什么能阻止指令重新排序:特别是可以对resource的两个读取进行重新排序( if有一个读取,而return有一个读取)。 因此,线程可以在if条件中看到非null resource ,但返回null引用(*)。 我认为UnsafeLazyInitialization.getInstance()可以返回null
  • 番石榴的ImmutableXXX真的不可变吗?(Is guava's ImmutableXXX really immutable?)
    问题 我已经使用番石榴已有一段时间了,并且对此感到非常信任,直到昨天我偶然发现了一个例子,这让我开始思考。 长话短说,这里是: public static void testGuavaImmutability(){ StringBuilder stringBuilder = new StringBuilder("partOne"); ImmutableList<StringBuilder> myList = ImmutableList.of(stringBuilder); System.out.println(myList.get(0)); stringBuilder.append("appended"); System.out.println(myList.get(0)); } 运行此命令后,您可以看到ImmutableList内部的条目的值已更改。 如果此处涉及两个线程,则一个线程可能碰巧看不到另一个线程的更新。 同样令我非常不耐烦的是,Effective Java中的Item15,第5点是这样说的: 在构造函数中创建防御副本-这似乎很合逻辑。 查看ImmutableList的源代码,我看到以下内容: SingletonImmutableList(E element) { this.element = checkNotNull(element); } 因此
  • C# (.NET) 设计缺陷(C# (.NET) Design Flaws [closed])
    问题 就目前而言,这个问题不适合我们的问答形式。 我们希望答案得到事实、参考或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。 如果您觉得此问题可以改进并可能重新打开,请访问帮助中心以获取指导。 9年前关闭。 C# 或 .NET Framework 中的一些最大设计缺陷是什么? 示例:不存在不可为空的字符串类型,您必须在从 IDataReader 获取值时检查 DBNull。 回答1 我强烈同意这篇文章(对于那些因缺少 ToString 而大便的人,有一个 debugger 属性可以为您的类提供自定义格式)。 在上述列表的顶部,我还将添加以下合理的要求: 不可为空的引用类型作为可空值类型的补充, 允许覆盖结构的空构造函数, 允许泛型类型约束指定密封类, 我同意这里的另一张海报,它在用作约束时要求任意构造函数签名,即。 其中T : new(string) ,或 where T : new(string, int) 我也同意这里关于修复事件的另一张海报,包括空事件列表和并发设置(尽管后者很棘手), 运算符应该定义为扩展方法,而不是类的静态方法(或者至少不只是静态方法), 允许接口的静态属性和方法(Java 有这个,但 C# 没有), 允许在对象初始值设定项中进行事件初始化(目前仅允许字段和属性), 为什么“对象初始值设定项”语法仅在创建对象时可用? 为什么不随时提供它
  • 在python字典中赋值(复制与参考)(assigning value in python dict (copy vs reference))
    问题 我了解在python中,任何东西,无论是数字,字符串,字典还是其他任何东西都是对象。 变量名只是指向内存中的对象。 现在根据这个问题, >> a_dict = b_dict = c_dict = {} 这将创建一个空字典,并且所有变量都指向该dict对象。 因此,更改任何一个都会反映在其他变量中。 >> a_dict["key"] = "value" #say >> print a_dict >> print b_dict >> print c_dict 会给 {'key': value} {'key': value} {'key': value} 我已经了解了指向对象的变量的概念,因此这似乎很公平。 现在,尽管它很奇怪,但由于它是这样一个基本的陈述,为什么会发生这种情况? >> a = b = c = 1 >> a += 1 >> print a, b, c 2, 1, 1 # and not 2, 2, 2 问题的第一部分:为什么这里不应用相同的概念? 实际上,当我尝试为此寻求解决方案时,就出现了这种疑问: >> a_dict = {} >> some_var = "old_value" >> a_dict['key'] = some_var >> some_var = "new_value" >> print a_dict {'key': 'old_value'} #
  • 不变类的例子(Examples of immutable classes)
    问题 我已经知道不可变类的定义,但是我需要一些示例。 回答1 标准API中一些著名的不可变类: java.lang.String(已经提到) 基本类型的包装器类:java.lang.Integer,java.lang.Byte,java.lang.Character,java.lang.Short,java.lang.Boolean,java.lang.Long,java.lang.Double, java.lang.Float java.lang.StackTraceElement(用于构建异常stacktraces) 大多数枚举类是不可变的,但实际上这取决于具体情况。 (不要实现可变的枚举,这会在某种程度上使您搞砸。)我认为,至少标准API中的所有枚举类实际上都是不可变的。 java.math.BigInteger和java.math.BigDecimal(至少这些类本身的对象,子类可能会引入可变性,尽管这不是一个好主意) java.io.File。 请注意,这表示VM外部的对象(本地系统上的文件),该对象可能存在也可能不存在,并且具有一些方法可以修改和查询此外部对象的状态。 但是File对象本身保持不变。 (java.io中的所有其他类都是可变的。) java.awt.Font-表示用于在屏幕上绘制文本的字体(可能有一些可变的子类,但这肯定没有用) java.awt
  • 为什么在Python中没有“ const”? [关闭](Why no 'const' in Python? [closed])
    问题 从目前的情况来看,这个问题不适合我们的问答形式。 我们希望答案会得到事实,参考或专业知识的支持,但是这个问题可能会引起辩论,争论,民意测验或进一步的讨论。 如果您认为此问题可以解决并且可以重新提出,请访问帮助中心以获取指导。 7年前关闭。 我来自C语言背景,正在学习Python。 缺乏显式的类型安全性令人不安,但是我已经习惯了。 面对动态语言的所有优点,缺乏内置的基于契约的编程(纯抽象类,接口)的不足已成为一种习惯。 但是,无法请求const-cortectness使我发疯! 为什么Python中没有常量? 为什么不鼓励使用类级常量? 回答1 C和Python属于两种不同的语言类别。 前一个是静态类型的。 后者是动态的。 在静态类型的语言中,类型检查器能够推断每个表达式的类型,并在“编译”阶段检查它是否与给定的声明匹配。 在动态类型语言中,所需的类型信息直到运行时才可用。 表达式的类型可能因一次运行而异。 当然,您可以在程序执行期间添加类型检查。 这不是在Python中做出的选择。 这具有允许“鸭式打字”的优点。 缺点是解释器无法检查类型正确性。 关于const关键字。 这是一个类型修饰符。 限制允许使用的变量(有时修改允许的编译器优化)。 在运行时检查动态语言似乎效率很低。 在最初的分析中,这将意味着针对每种影响检查一个变量是否为const 。 可以对它进行优化
  • Emacs 中 perl 的语法高亮显示已损坏,有修复吗?(Syntax highlight for perl in Emacs is broken, is there a fix?)
    问题 我是一个 perl 程序员和一个新的 emacs 用户。 我在 Windows 下,使用 cperl-mode 编辑 perl。 Emacs 版本是 24.2.1。 这是带有一些示例代码的屏幕截图: (来源:breqwas.net) 明显的错误:它突出显示 ( a => "b" ) 样式列表中的数组、散列和未引用的文字值另一个错误:由于非默认引号符号,它将正则表达式中的第一个单词高亮显示为数组不是错误,但看起来很奇怪:它会在使用时随时突出显示数组和散列(即使在注释中,呵呵),但只有在声明时才会突出显示标量不是错误,但看起来很奇怪:与函数相同的故事:在声明时突出显示,而不是在调用时突出显示不是错误,但看起来很奇怪:为什么“打印”、“说”和“系统”有不同的颜色? 我可以继续前进,但我希望这能很好地解释“破碎”这个词。 然后我学会了神奇的 Cu Cx = 组合键,它显示了光标下文本的文本属性,希望能做出更好的自己的配色方案。 在这一点上,它开始变得更没有意义了。 “打印”有 。 "die" 有 。 同时,两者都是函数,可以(并且经常)被覆盖。 “系统”具有 。 为什么? 函数声明有 - 没关系,但是“use”的参数也是如此。 为什么? 函数调用和标量根本没有 face 属性,无法突出显示。 为什么? 等等,等等。再一次,我可以继续前进。 有没有办法解决所有这些问题?
  • 不可变的只读引用类型和FXCop违规:不要声明只读的可变引用类型(Immutable readonly reference types & FXCop Violation: Do not declare read only mutable reference types)
    问题 我一直在努力解决这种FXCop违规行为“ DoNotDeclareReadOnlyMutableReferenceTypes” MSDN:http://msdn.microsoft.com/en-us/library/ms182302%28VS.80%29.aspx 来自MSDN的代码,这将导致此违规: namespace SecurityLibrary { public class MutableReferenceTypes { static protected readonly StringBuilder SomeStringBuilder; static MutableReferenceTypes() { SomeStringBuilder = new StringBuilder(); } } } 从Jon在这里和这里的答案中,我了解到持有对对象(在本例中为SomeStringBuilder)的引用的字段是只读的,而不是对象本身(由new StringBuilder()创建) 因此,以该示例为例,一旦字段引用了对象,我将如何更改它本身? 我喜欢埃里克·利珀特(Eric Lippert)的示例,该示例说明了如何更改只读数组,并且希望对任何其他可变引用类型都看到类似的内容 回答1 由于问题中提供了MutableReferenceTypes类
  • Java最终编辑(Java final modifier)
    问题 有人告诉我,我误解了final 。 final关键字有什么作用? 这是我的想法的简短概述,我知道: Java最终修饰符(又名聚合关系) 原始变量:只能设置一次。 (内存和性能提升) 对象变量:可以修改,最终适用于对象引用。 字段:只能设置一次。 方法:不能被覆盖,隐藏。 类别:无法扩展。 垃圾收集:将强制Java代垃圾收集标记扫描进行两次扫描。 罐头和罐头 会使克隆失败(这既好又坏) 可以使不可变的原语又称为const 可以使空白不可变-在创建时初始化为aka只读可以使对象浅成不变可以使范围/可见性不变可以减少方法调用的开销(因为它不需要虚拟表) 可以将方法参数用作最终参数(即使您不是) 可以使对象成为线程安全的(如果将对象定义为final,则不会使方法参数成为final) 可以进行模拟测试(不是您可以做任何事-您可以说是故意的错误) 不能交朋友(与其他朋友可变而不能休息) 以后不能使可变成为不变的(但是可以使用工厂模式,例如修复) 不能使数组元素不可变又称为深度不可变无法创建对象的新实例(这既好又坏) 无法使序列化工作 没有替代final ,但是有wrapper + private和enums。 回答1 依次回答您的每个观点: 原始变量:只能设置一次。 (内存和性能提升) 是的,但是没有增加内存,也没有提高性能。 (您假定的性能提升仅来自设置一次,而不是来自final 。)
  • 为什么在 ES5 中将变量对象更改为词法环境?(Why variable object was changed to lexical environment in ES5?)
    问题 ES5 将变量对象(VO)更改为词法环境。 VO作为感知已经很明显了,这种变化的动机是什么? 回答1 我认为变量对象更类似于环境记录。 环境记录记录在其关联词法环境范围内创建的标识符绑定。 在 ES5 中有两种不同的环境记录: 声明性环境记录用于定义 ECMAScript 语言句法元素的效果,例如FunctionDeclarations 、 VariableDeclarations和Catch子句,它们直接将标识符绑定与 ECMAScript 语言值相关联。 对象环境记录用于定义 ECMAScript 元素(例如Program和WithStatement)的效果,这些元素将标识符绑定与某些对象的属性相关联。 所以问题是为什么要引入声明性环境记录,而不是像 ES3 变量对象那样只使用对象环境记录。 不同之处在于声明性环境记录可以具有不可变的绑定: 除了所有环境记录支持的可变绑定之外,声明性环境记录还提供不可变绑定。 不可变绑定是一种标识符和值之间的关联一旦建立就不能修改的绑定。 不可变绑定在对象中没有直接等价物。 一个属性可以被定义为不可配置和不可写,变得不可变。 然而, 不可变绑定的创建和初始化是不同的步骤,因此此类绑定可能存在于已初始化或未初始化状态。 但是你不能有一个未初始化的属性。 如果您定义了一个不可配置的不可写属性,其值为 undefined
  • 如何识别Java中的不可变对象(How do I identify immutable objects in Java)
    问题 在我的代码中,我正在创建一个对象集合,各个线程将以一种仅在对象是不可变的情况下才安全的方式访问这些对象。 当试图将一个新对象插入到我的集合中时,我想测试一下它是否是不可变的(如果不是不变的,我将抛出一个异常)。 我可以做的一件事是检查一些众所周知的不可变类型: private static final Set<Class> knownImmutables = new HashSet<Class>(Arrays.asList( String.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Boolean.class, BigInteger.class, BigDecimal.class )); ... public static boolean isImmutable(Object o) { return knownImmutables.contains(o.getClass()); } 这实际上使我省了90%的路,但是有时我的用户会想要创建自己的简单不可变类型: public class ImmutableRectangle { private final int width; private final int height; public
  • Swift mutable dictionary being treated as immutable
    I am trying to implement In App Purchases, and I am tracking which purchases a user has purchased via NSUserDefaults. I have a function that sets the values of each purchase, but when it runs, I get an error saying that I am mutating the dictionary of purchase values even though the dictionary is declared with a var instead of a let and is an NSMutableDictionary. Sometimes it does work, but most of the time it doesn't. I get a few warnings about declaring my variables with let instead of var, but I ignore them to give my variables maximum mutability. Why does this not work? The error I get is
  • 最终的ArrayList是什么意思?(what is the sense of final ArrayList?)
    问题 通过使ArrayList(或其他Collection)成为最终形式,我们可以获得哪些优点/缺点? 我仍然可以将新元素添加到ArrayList中,删除元素并进行更新。 但是,什么才是最终的效果呢? 回答1 但是,什么才是最终的效果呢? 这意味着您无法将变量重新绑定为指向其他集合实例: final List<Integer> list = new ArrayList<Integer>(); list = new ArrayList<Integer>(); // Since `list' is final, this won't compile 出于风格考虑,我将大多数我不打算更改的引用声明为final 。 我仍然可以将新元素添加到ArrayList中,删除元素并进行更新。 如果愿意,可以使用Collections.unmodifiableList()防止插入,删除等操作: final List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>(...)); 回答2 这仅意味着您无法重新分配其参考。 尝试执行以下操作将导致编译器错误。 final List<String> list = new ArrayList<String>(); list = new LinkedList<String>()
  • 优点 /缺点不变性与可变性的关系(Pros. / Cons. of Immutability vs. Mutability)
    问题 好吧,我想这显然是我试图为此推理的方向。 如今,尽可能多地谈论不变性(不变性)的优点。 Java的并发编程书籍也对此进行了很多讨论。 但是,所有这些只是我所读到的。 我个人还没有用功能语言编写太多代码。 对于我来说,可以与不可变的对象舒适地工作是非常令人惊讶的。 从理论上讲,这绝对是可能的。 但是,从实际的角度来看,这是一种非常舒适的体验。 或者,我必须开发什么新的推理方法(对于FP),这样我就不需要太多的可变性了。 我将不胜感激,当您被迫使用不可变对象时,如何考虑编写程序。 已经将其作为社区Wiki ...供所有有兴趣解决此问题或将其标记为主观...等的人。 回答1 许多功能语言都不是纯语言(允许突变和副作用)。 以f#为例,如果您查看集合中的某些非常底层的结构,您会发现其中一些在幕后使用迭代,而另一些则使用某种可变状态(如果您想使用的前n个元素一个序列,例如拥有一个计数器要容易得多)。 诀窍是通常可以做到这一点: 谨慎使用提请您注意何时做注意在f#中如何必须声明可变的东西 它能够在很大程度上避免突变状态是由大量的功能码有证明的。 对于使用命令式语言的人来说,这有点难以理解,尤其是以前以循环的形式将代码作为递归函数编写。 然后,甚至更棘手的是在可能的情况下将它们编写为尾递归。 知道如何做到这一点是有益的,并且可以导致更具表现力的解决方案侧重于逻辑而不是实现。
  • 暴露一个不可变对象的状态可以吗?(Is it okay to expose the state of an Immutable object?)
    问题 最近遇到了不可变对象的概念,我想知道控制对状态的访问的最佳实践。 尽管我大脑中面向对象的部分让我想在看到公众成员时害怕而畏缩,但我认为这样的事情没有技术问题: public class Foo { public final int x; public final int y; public Foo( int x, int y) { this.x = x; this.y = y; } } 我会更舒服地将字段声明为private并为每个字段提供 getter 方法,但是当状态显式为只读时,这似乎过于复杂。 提供对不可变对象状态的访问的最佳实践是什么? 回答1 这完全取决于您将如何使用该对象。 公共字段本质上并不是邪恶的,将所有内容都默认为公共字段是不好的。 例如 java.awt.Point 类公开了它的 x 和 y 字段,它们甚至不是最终的。 您的示例似乎很好地使用了公共字段,但是您可能不想公开另一个不可变对象的所有内部字段。 没有包罗万象的规则。 回答2 过去我也这么认为,但通常最终将变量设为私有并使用 getter 和 setter,这样以后我仍然可以选择在保持相同接口的同时对实现进行更改。 这确实让我想起了我最近在 Robert C. Martin 的“Clean Code”中读到的一些东西。 在第 6 章中,他给出了一个略有不同的观点。 例如,在第 95 页他说