当前位置: 首页 > 面试题库 >

Java中“私有静态最终”和“公共静态最终”类变量的最接近Ruby表示?

章远航
2023-03-14
问题内容

给定下面的Java代码,您可以static final在Ruby类中最接近地表示这两个变量吗?而且,在Ruby中是否可以像Java中那样区分private staticpublic static变量?

public class DeviceController
{
  ...
  private static final Device myPrivateDevice = Device.getDevice("mydevice");
  public static final Device myPublicDevice = Device.getDevice("mydevice");
  ...
  public static void main(String args[])
  {
   ...
  }
}

问题答案:

Ruby中确实没有等效的构造。

但是,您似乎犯了一个经典的移植错误:您有一种使用语言A 的 解决方案 ,然后尝试将其翻译为语言B,这时您真正应该做的就是找出 问题
,然后找出解决方法使用语言B。

我不能完全确定您要从那个小的代码段中解决什么问题,但是这里有 一个 关于如何在Ruby中实现它的可能想法:

class DeviceController
  class << self
    def my_public_device;  @my_public_device  ||= Device['mydevice'] end

    private

    def my_private_device; @my_private_device ||= Device['mydevice'] end
  end
end

这是另一个:

class DeviceController
  @my_public_device  ||= Device['mydevice']
  @my_private_device ||= Device['mydevice']

  class << self
    attr_reader :my_public_device, :my_private_device
    private :my_private_device
  end
end

(不同之处在于,第一个示例是惰性的,仅在首次调用相应的属性读取器时才初始化实例变量。第二个示例将在类主体执行后立即对其进行初始化,即使它们不再需要也是如此,就像Java版本。)

让我们在这里讨论一些概念。

在Ruby中,就像其他所有“适当”(针对“适当”的各种定义)面向对象语言一样,状态(实例变量,字段,属性,插槽,属性,无论您想称呼它们如何) 始终是
私有的。有 没有办法 从外部访问它们。与对象通信的唯一方法是通过发送消息。

[注:每当我写“没有办法”,“总是”,“唯一的办法”等字眼时,实际上它的意思是“没有办法,除了反射”。在这种特定情况下,Object#instance_variable_set例如有。]

换句话说:在Ruby中,变量始终是私有的,访问它们的唯一方法是通过getter和/或setter方法,或者在Ruby中将其称为属性读取器和/或写入器。

现在,我继续写 实例变量 ,但是在Java示例中,我们有 静态字段 ,即
变量。嗯,在Ruby中,与Java不同,类也是对象。它们是Class类的实例,因此,就像其他任何对象一样,它们可以具有实例变量。因此,在Ruby中,类变量的等效项实际上只是一个标准实例变量,属于一个恰好是类的对象

(也有类层次结构变量,在符号上用双符号表示@@sigil。它们确实很奇怪,您可能应该忽略它们。类层次结构变量在整个类层次结构(即它们所属的类,所有子类和它们的子类及其子类…以及所有这些类的所有实例。实际上,它们更像是全局变量而不是类变量,应该真正地调用它们$$var而不是@@var,因为它们与实例的关系更紧密地与全局变量相关变量。它们并不是完全没用,但很少有用。)

因此,我们介绍了“字段”部分(Java字段== Ruby实例变量),介绍了“ public”和“
private”部分(在Ruby中,实例变量始终是私有的,如果您想将它们设为公开,使用公共的getter /
setter方法),我们已经介绍了“静态”部分(Java静态字段== Ruby类实例变量)。那“最后”部分呢?

在Java中,“最终”只是拼写“ const”的一种有趣方式,html" target="_blank">设计人员避免了这种做法,因为const诸如C和C
++之类的语言中的关键字被巧妙地打乱了,他们不想使人们感到困惑。Ruby 确实
有常量(以大写字母开头)。不幸的是,它们并不是真正恒定的,因为在生成警告的同时尝试对其进行修改实际上是可行的。因此,它们更像是约定,而不是编译器强制的规则。但是,常量的更重要限制是它们始终是公共的。

因此,常数几乎是完美的:它们不能被修改(嗯,它们 不应该
被修改),即它们是final,它们属于一个类(或模块),即它们是static。但是它们始终是public,因此很遗憾,它们不能用于建模private static final字段。

这正是思考问题而不是解决方案的关键所在。您想要什么?你想说

  1. 属于一个阶级
  2. 只能读不写
  3. 仅初始化一次,
  4. 可以是私人的也可以是公共的。

您可以用Java中完全不同的方式实现所有这些目标:

  1. 类实例变量
  2. 不提供setter方法,仅提供getter方法
  3. 使用Ruby的||=复合分配仅分配一次
  4. 吸气法

您唯一需要担心的是,您没有分配给@my_public_device任何地方,或者更好的是,根本没有访问它。始终使用getter方法。

是的,这
实施中的一个漏洞。Ruby通常被称为“成年语言”或“成人同意语言”,这意味着您不必让编译器强制执行某些事情,而只是将它们放在文档中,并完全相信您的开发人员已经学会了与其他人接触人民私下很粗鲁…

一种完全 不同的
隐私保护方法是功能语言中使用的一种:使用闭包。闭包是关闭了其词法环境的代码块,即使该词法环境已超出范围。这种实现私有国家的方法在Scheme中非常流行,但是最近也被Douglas
Crockford等人推广。用于JavaScript。这是Ruby中的示例:

class DeviceController
  class << self
    my_public_device, my_private_device = Device['mydevice'], Device['mydevice']

    define_method :my_public_device  do my_public_device  end
    define_method :my_private_device do my_private_device end

    private :my_private_device
  end # <- here the variables fall out of scope and can never be accessed again
end

请注意,与我的答案顶部的版本之间的细微但重要的区别是:缺少@标记。在这里,我们正在创建 局部 变量,而不是 实例
变量。类主体结束后,这些局部变量将超出范围,并且永远无法再次访问。 只有
它定义两个getter方法两大块仍然可以访问他们,因为他们接近了类体。现在,它们 实际上是 私有的
它们是final,因为在整个程序中唯一仍然可以访问它们的就是纯 吸气 方法。

这可能不是惯用的Ruby,但是对于任何具有Lisp或JavaScript背景的人来说,它应该足够清楚。这也非常优雅。



 类似资料:
  • 问题内容: 我碰巧在工作场所遇到了Java代码。这是场景:有2个类- 和。 除了4个公共静态最终字符串值外,没有任何内容。它的目的是使用类似的值(不要问我为什么,这不是我的代码)。 进口。我在其中编辑了字符串值并对其进行了编译。当我运行时,我可以看到它正在使用旧值- 而不是新值。我不得不重新编译以使其使用来自的新值!(我不得不重新编译其他导入的类!) 这是仅因为JDK 1.6还是我早就应该知道重新

  • 问题内容: 将变量声明为的区别是什么 要么 如果我只希望变量是局部的,并且是常量(以后不能更改)? 谢谢 问题答案: 仅仅具有预期的效果。 声明static使其成为一个类变量,使其可以使用类名进行访问

  • 问题内容: 我一直想知道Java中的单例。按照惯例,单例设置如下: 最近,我切换到使用以下内容: 由于没有空检查,因此它更短,更快捷,而且打字对我来说比打字好。有什么理由不能使第二种方法成为主流呢? 问题答案: 第一个版本在第一次实际需要时创建实例,而第二个版本(较短的版本)在初始化类后立即运行构造函数 类或接口类型T将在以下任何一种首次出现之前立即初始化: T是一个类,并创建T的实例。 T是一个

  • 问题内容: 我找到了一个代码,它声明了如下代码 它们之间有什么区别或相同?还是与或不同? 问题答案: 完全没有区别。根据 Java语言规范的8.3.1-类-字段修饰符, 如果两个或多个(不同的)字段修饰符出现在字段声明中,则按惯例(尽管不是必需的),它们的出现顺序与上面FieldModifier生产中所示的顺序一致。 对于字段,所述生产按以下顺序列出修饰符: 对于方法:

  • 问题内容: 在Java中,何时应使用静态非最终变量? 例如 显然,这里我们不是在谈论常量。 根据我的经验,我经常在使用单例时对它们进行辩护,但后来我最终需要拥有多个实例,这使我感到非常头痛和重构。 似乎很少在实践中使用它们。你怎么看? 问题答案: 统计信息收集可以使用非最终变量,例如,计算创建的实例数。另一方面,对于这种情况,您可能还是要使用etc,这时可能是最终的。另外,如果您要收集多个统计信息

  • 问题内容: 通常,最终静态成员,尤其是变量(或静态最终变量,当然可以以任何顺序使用,而不会重叠含义)已广泛用于Java接口中,以定义实现类的 协议行为 ,这意味着实现该类的类(继承)接口必须包含该接口的所有成员。 我无法区分 final 和 final静态 成员。final静态成员是一个声明为final或其他东西的静态成员?在哪些特定情况下应专门使用它们? 永远不能在方法内部,静态方法内部或实例方