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

时间:2017-10-31 19:04:07

标签: java c#

在Java中,

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

我在Does `final` means a field is not mutable?

问了那个问题

C#中的readonly是否也对值类型和引用类型的变量进行相同的区分?

感谢。

3 个答案:

答案 0 :(得分:3)

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

Java的“最终”行为

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

C#“readonly”行为

readonly关键字是您只能在字段上使用的修饰符。给定一个使用readonly修饰符声明的变量,声明引入的字段的任何赋值只能作为声明的一部分或在同一个类的构造函数中出现。

Readonly修饰符可防止更改字段。因此,不允许任何后来改变它们的企图。

答案 1 :(得分:1)

  

在Java中,

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

C#中的readonly是否也对值类型和引用类型的变量进行相同的区分?

大多数情况都是如此,是的。在离开构造函数后,finalreadonly字段都不会被修改:可能不会将引用类型字段指定为指向其他对象,并且可能不会为值类型字段分配不同的值。但那不是全部。

虽然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不会也不会影响" internal& #34;这种可变性。

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

编译时间常数

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

反思修改

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

局部变量和形式参数

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

[1] 或者,可以在实例初始值设定项块中分配一次final字段。但是,这些很少使用,并且使用实例初始值设定项等同于将块的内容添加到每个实例构造函数的开头。

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

答案 2 :(得分:0)

readonly不区分引用类型或值类型。 readonly只是意味着无法在字段初始值设定项或构造函数之外更改存储在变量中的

是什么让您认为有必要区分价值和参考类型?变量是的占位符,无论其类型如何。 该值是或代表什么是另一个故事。