[英]Does `readonly` in C# also make the same distinction between variables of value types and reference types as `final` in Java?
在Java中,
final
修改的引用类型的变量不能更改为引用任何其他对象 final
修改的原始类型的变量不能更改为具有不同的值 C#中的readonly
是否也将值类型的变量和引用类型的变量区分开?
谢谢。
当C#中的readonly
用作变量的修饰符时,它等效于Java的final
因此对于它们各自的语言中的值类型和引用类型,它们的行为完全相同。
您只能一次且只能一次初始化一个最终变量。 这与是否可以修改对象状态无关。
readonly
关键字是只能在字段上使用的修饰符。 给定一个使用readonly
修饰符声明的变量,对该声明引入的字段的任何赋值只能作为声明的一部分或在同一类的构造函数中进行。
Readonly
修饰符可防止更改字段。 因此,不允许以后再尝试更改它们。
在Java中,
- 由final修改的引用类型的变量不能更改为引用任何其他对象
- 由final修改的原始类型的变量不能更改为具有不同的值
C#中的readonly是否也将值类型的变量和引用类型的变量区分开?
多数情况下是这样。 离开构造函数后,不得修改final
字段或readonly
字段:可能不会将引用类型字段分配为指向其他对象,并且不会为值类型字段分配其他值。 但这还不是全部。
尽管Java的final
和C#的readonly
修饰符在很大程度上达到了相同的目的,但您应该注意一些差异。
必须使用内联字段初始化程序或在每个构造函数中通过赋值在Java中的final
字段精确地赋值一次 [1] 。 C#中的readonly
字段只能内联或在构造函数中初始化,但是对可以分配多少次没有限制。 它可能被分配一次,多次或从不分配。
值类型的readonly
字段与引用类型的行为之间存在细微的行为差异。 当值类型字段标记为readonly
,对该字段的任何访问都会导致进行复制。 这样可以防止您对字段本身执行任何可能的变异操作,从而有效地使其内部不可变 。 例如:
struct TestStruct {
public int Count;
public int Increment() { return ++Count; }
}
class MutableTest {
TestStruct s;
public void Test() {
Console.WriteLine(s.Increment());
}
}
class ImmutableTest {
readonly TestStruct s;
public void Test() {
Console.WriteLine(s.Increment());
}
}
如果您声明一个MutableTest
并两次调用Test()
,您将看到它先显示1
然后显示2
。 做同样与ImmutableTest
实例,你会看到1
,然后1
一次。
但是请注意,Java没有用户定义的值类型的概念:Java中的所有值类型都是不可变的基元,因此将基元字段声明为final
不会并且不会以这种方式影响“内部”可变性。
修饰符都不会影响引用类型的内部可变性,例如,添加final
或readonly
修饰符本身不会阻止您修改目标对象的字段或属性,也不会阻止您调用可能使对象发生变异的方法。
与readonly
不同, final
修饰符可以与static
组合以定义编译时常量。 如果static final
字段具有原始值或String
值,并且其内联初始化器是编译时常量表达式,则编译器可以用基础常量值替换对其的任何引用。 在这种情况下,实际上不会读取该字段。 在C#中使用const
关键字也可以实现相同的目的。 它不能用readonly
完成。
值得注意的是, readonly
字段可以通过反射进行修改。 这有效地绕过了仅在对象构造期间分配readonly
字段的要求。 在Java中并非如此:尝试以反射方式修改final
字段将触发异常。
最后,在Java中,形式方法参数和局部变量可以标记为final
。 严格来说,这是语言级别的功能,它对生成的字节码[2]没有影响。 final
变量(如字段)必须精确分配一次。 对于局部变量或形式参数,C#不等同于readonly
或final
。
[1]或者,可以在实例初始化程序块中分配一次final
字段。 但是,很少使用它们,使用实例初始化器等效于将块的内容放在每个实例构造函数的开头。
[2]从技术上讲,在某些情况下,形式参数的final
指定可以记录在元数据表中,但是方法主体内的字节码不受影响。
readonly
在引用类型或值类型之间没有区别。 readonly
仅表示存储在变量中的值不能在字段初始化程序或构造函数外部更改。
是什么使您认为有必要区分值和引用类型? 变量是值的占位符,无论其类型如何。 什么是价值或代表则是另一回事。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.