繁体   English   中英

C#中的`readonly`在值类型和引用类型的变量上是否也与Java中的`final`相同?

[英]Does `readonly` in C# also make the same distinction between variables of value types and reference types as `final` in Java?

在Java中,

  • final修改的引用类型的变量不能更改为引用任何其他对象
  • final修改的原始类型的变量不能更改为具有不同的值

我问“ final”是否表示字段不可变?

C#中的readonly是否也将值类型的变量和引用类型的变量区分开?

谢谢。

当C#中的readonly用作变量的修饰符时,它等效于Java的final因此对于它们各自的语言中的值类型和引用类型,它们的行为完全相同。

Java的“最终”行为

您只能一次且只能一次初始化一个最终变量。 这与是否可以修改对象状态无关。

C#“只读”行为

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不会并且不会以这种方式影响“内部”可变性。

修饰符都不会影响引用类型的内部可变性,例如,添加finalreadonly修饰符本身不会阻止您修改目标对象的字段或属性,也不会阻止您调用可能使对象发生变异的方法。

编译时常数

readonly不同, final修饰符可以与static组合以定义编译时常量。 如果static final字段具有原始值或String值,并且其内联初始化器是编译时常量表达式,则编译器可以用基础常量值替换对其的任何引用。 在这种情况下,实际上不会读取该字段。 在C#中使用const关键字也可以实现相同的目的。 它不能用readonly完成。

反射修改

值得注意的是, readonly字段可以通过反射进行修改。 这有效地绕过了仅在对象构造期间分配readonly字段的要求。 在Java中并非如此:尝试以反射方式修改final字段将触发异常。

局部变量和形式参数

最后,在Java中,形式方法参数和局部变量可以标记为final 严格来说,这是语言级别的功能,它对生成的字节码[2]没有影响。 final变量(如字段)必须精确分配一次。 对于局部变量或形式参数,C#不等同于readonlyfinal


[1]或者,可以在实例初始化程序块中分配一次final字段。 但是,很少使用它们,使用实例初始化器等效于将块的内容放在每个实例构造函数的开头。

[2]从技术上讲,在某些情况下,形式参数的final指定可以记录在元数据表中,但是方法主体内的字节码不受影响。

readonly在引用类型或值类型之间没有区别。 readonly仅表示存储在变量中的不能在字段初始化程序或构造函数外部更改。

是什么使您认为有必要区分值和引用类型? 变量是值的占位符,无论其类型如何。 什么是价值或代表则是另一回事。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM