13

在 Scala 中,我们可以写

object Foo { def bar = {} }

编译器是如何实现的?我可以Foo.bar();从 Java 调用,但从new Foo();Java 给出错误cannot find symbol symbol: constructor Foo()

  • JVM 是否原生支持单例?
  • 是否可以在 Java 中有一个没有构造函数的类?

注意:这里是输出的代码scalac -print

package <empty> {
  final class Foo extends java.lang.Object with ScalaObject {
    def bar(): Unit = ();
    def this(): object Foo = {
      Foo.super.this();
      ()
    }
  }
}
4

3 回答 3

23

编译代码时,Scala 编译器生成与以下 Java 代码等效的代码:

public final class Foo {
    private Foo() {} // Actually, Foo doesn't have constructor at all
                     // It can be represented in bytecode, 
                     // but it cannot be represented in Java language

    public static final void bar() {
        Foo$.MODULE$.bar();
    }
}

public final class Foo$ implements ScalaObject {
    public static final Foo$ MODULE$;
    static {
        new Foo$();
    }
    private Foo$() { MODULE$ = this; }
    public final void bar() {
        // actual implementation of bar()
    }
}

Foo$是一个单例的实际实现,同时Foo提供了static一种与 Java 交互的方法。

于 2011-10-19T10:44:19.247 回答
12

对单例的支持不在语言级别,但该语言提供了足够的设施来创建它们而不会遇到任何麻烦。

考虑以下代码:

public class Singleton {
    private static final Singleton instance = new Singleton();

    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

这是来自 Wikipedia 的示例,它解释了如何制作单例。实例保存在私有字段中,构造函数在类外部不可访问,该方法返回此单个实例。

至于构造函数:默认情况下,每个类都有一个所谓的默认构造函数,它不带参数,只是调用超类的无参数构造函数。如果超类没有任何不带参数的可访问构造函数,则必须编写显式构造函数。

所以一个类必须有一个构造函数,但是如果超类有一个无参数的构造函数,你就不必编写它。

于 2011-10-19T10:36:20.330 回答
4

Joshua Bloch 在“Effective Java”一书中推荐使用枚举来实现单例。

请参阅这个问题: 在 Java 中实现单例模式的有效方法是什么?

于 2011-10-19T11:25:25.473 回答