Scala中的包私有范围可从Java中看到

Dic*_*ici 13 java scala bytecode package-private apache-spark

我刚刚从Java代码中使用Scala代码生成的字节码时,我发现Scala范围很奇怪.请考虑使用Spark(Spark 1.4,Hadoop 2.6)的以下代码段:

import java.util.Arrays;
import java.util.List;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.broadcast.Broadcast;

public class Test {
    public static void main(String[] args) {
        JavaSparkContext sc = 
            new JavaSparkContext(new SparkConf()
                                .setMaster("local[*]")
                                .setAppName("test"));

        Broadcast<List<Integer>> broadcast = sc.broadcast(Arrays.asList(1, 2, 3));

        broadcast.destroy(true);

        // fails with java.io.IOException: org.apache.spark.SparkException: 
        // Attempted to use Broadcast(0) after it was destroyed
        sc.parallelize(Arrays.asList("task1", "task2"), 2)
          .foreach(x -> System.out.println(broadcast.getValue()));
    }
}
Run Code Online (Sandbox Code Playgroud)

这段代码失败了,这是因为我Broadcast在使用它之前自愿销毁它,但问题是在我的心理模型中它甚至不应该编译,更不用说运行正常了.

事实上,Broadcast.destroy(Boolean)声明是private[spark]这样,它不应该从我的代码可见.我会尝试查看字节码,Broadcast但这不是我的专长,这就是我更喜欢发布这个问题的原因.另外,抱歉,我太懒了,不能创建一个不依赖Spark的例子,但至少你明白了.请注意,我可以使用Spark的各种package-private方法,它不仅仅是Broadcast.

知道发生了什么事吗?

Yuv*_*kov 21

如果我们用一个更简单的例子重建这个问题:

package yuvie

class X {
  private[yuvie] def destory(d: Boolean) = true
}
Run Code Online (Sandbox Code Playgroud)

并在Java中反编译:

[yuvali@localhost yuvie]$ javap -p X.class 
Compiled from "X.scala"
public class yuvie.X {
  public boolean destory(boolean);
  public yuvie.X();
}
Run Code Online (Sandbox Code Playgroud)

我们看到private[package]Scala变成public了Java.为什么?这是因为Java私有包不等同于Scala私有包.这篇文章有一个很好的解释:

重要的区别是Scala中的'private [mypackage]' 不是 Java包私有的,不管它看起来多么像它.Scala包是真正的分层,'private [mypackage]'允许访问类和对象,直到 "mypackage"(包括可能介于其间的所有分层包).(我没有这方面的Scala规范参考,我在这里的描述可能很模糊,我正在使用[4]作为参考.)Java的包不是分层的,而package-private只允许访问该包中的类,以及原始类的子类,Scala的'private [mypackage]'不允许的东西.

因此,'package [mypackage]'对Java包私有的限制越来越少.出于这两个原因,JVM package-private不能用于实现它,并且允许Scala在编译器中公开的用法的唯一选项是"public".

  • @Antimony你是对的,但是使用反射的努力通常会让人觉得它不值得,不像简单地调用一个正确的方法.我同意这可能有问题. (6认同)
  • 任何想要访问他们不应该使用的东西的人都可以使用反射. (4认同)