【问题标题】:I can haz no package-private class in Scala?我可以在 Scala 中没有包私有类吗?
【发布时间】:2012-10-09 09:28:48
【问题描述】:

对不起,这个吸引人的标题。 ;-)

我想在 Scala 中创建一个带有包私有方法的包私有类,所以我的类看起来有点像这样:

package net.java.truevfs.ext.pace

import ...

private[pace] abstract class AspectController(controller: FsController)
extends FsDecoratingController(controller) {

  private[pace] def apply[V](operation: => V): V

  ... // lots of other stuff
}

但是,如果我使用 javap 检查 Scala 编译器有效创建的内容,我会得到如下结果:

$ javap -classpath target/classes net.java.truevfs.ext.pace.AspectController
Compiled from "AspectController.scala"
public abstract class net.java.truevfs.ext.pace.AspectController extends net.java.truevfs.kernel.spec.FsDecoratingController implements scala.ScalaObject{
    public abstract java.lang.Object apply(scala.Function0);
    ...
}

这意味着尽管 Scala 编译器可能尊重访问限制,但我仍然可以从任何 Java 代码调用这个类,这显然违反了封装。

我错过了什么吗? 有没有办法让这项工作按预期进行?

【问题讨论】:

    标签: scala


    【解决方案1】:

    除了@Régis 的回答之外,Scala 编译器不将类包私有的原因是因为根据 Scala 规则,它可以从其他包访问:即,@987654321 的子包@。例如

    package net.java.truevfs.ext.pace.subpackage
    import net.java.truevfs.ext.pace.AspectController
    
    class Subclass extends AspectController { ... }
    

    在 Scala 中是合法的,但在来自 net.java.truevfs.ext.pace.subpackage 的 Java 类中无法访问来自 net.java.truevfs.ext.pace 的包私有类。

    【讨论】:

    • 嗯,这实际上意味着在 Scala 中根本不存在包私有类的概念。太糟糕了,因为对我来说,它是我的 Java 工具集促进封装的主要元素(我知道这种保护无论如何只能在语言级别起作用)。
    • 我不能同时接受这两个答案,所以我选择了这个,因为它解释了为什么 Scala 编译器不能声明生成的代码包私有的访问修饰符——这不适用于访问修饰符的 Scala 语义.
    【解决方案2】:

    你没有错过任何东西。 scala 中的许多访问限制在 java 和 jvm 级别都没有等效项。附加信息显然就在 .class 文件中,但作为只有 scala 编译器会解释的自定义注释存在。 scala 对象模型只能部分匹配到 jvm 对象模型,java 编译器只会看到这个部分模型。 我想说匹配非常接近,scala 编译器在 java 互操作性方面做得很好,但没有什么是完美的。

    【讨论】:

    • 我是这么想的,并认出了课堂上的@scala.reflect.ScalaSignature 注释。不过让我担心的是,这明显违反了封装性,只要您可以从 Java 代码中调用任何内容,使用访问修饰符就完全没有意义。
    • 嗯,“无意义”的程度与访问修饰符通常无意义的程度相同,因为您始终可以通过反射/指针绕过它们。
    • 我不会说你可以从 java 调用“任何东西”。如果您将apply 设为纯私有(而不是pace 的私有),那么您会看到该方法确实在.class 文件中标记为私有。这是因为 scala 和 java 中私有方法的概念完全一样,所以编译器可以将其标记为私有。另一方面,包私有方法的概念在 java/jvm 中根本不存在。
    • 另外,@themel 关于访问限制是否毫无意义的问题是非常正确的。访问限制!=安全。它只是一个非常有用的工具(基于信任),您可以使用它帮助实现适当的封装以实现良好的工程设计。但它们几乎永远无法完全执行。在java中,受托人是jvm(而不仅仅是一个编译器),这是一件好事,但是(有点延伸)如果我将你的类加载到不检查访问的不兼容jvm中怎么办?或者在本机代码中,如果我通过指针访问某个私有字段?
    【解决方案3】:

    并不是一个 100% 正确的答案...

    如果我想用私有类做一些花哨的东西,你可以创建一个包对象。可以像访问任何其他包一样访问包对象。 MyClass 类是该包对象的包私有。 但是,它不是私有包。

    package object com.jasongoodwin.foo {
      private class MyClass
    
      class AnotherClass {
        val myClass = new MyClass
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-02-13
      • 2011-05-23
      • 2013-01-09
      • 1970-01-01
      • 1970-01-01
      • 2017-04-11
      • 2011-04-04
      • 2011-08-24
      • 2011-10-04
      相关资源
      最近更新 更多