Java JVM语言中的包

Java JVM语言中的包,java,scala,clojure,jvm,jvm-languages,Java,Scala,Clojure,Jvm,Jvm Languages,在Java中,类被放置在一个带有声明的包中,如package com.acme.foo,并将源文件放在子目录中,如com/acme/foo 我正在开发一种JVM语言,其风格要比Java更为独特,因此我将使用其中一种机制,但不能同时使用这两种机制,我想知道应该使用哪种机制 其他JVM语言如Scala和Clojure如何处理它?他们是否需要这两种机制,或者只需要一种机制,如果是这样的话, < P>我除了Culjueor没有什么经验,但我确实有斯卡拉的经验,Scala也使用子目录作为它们的包,但是其中

在Java中,类被放置在一个带有声明的包中,如
package com.acme.foo
,并将源文件放在子目录中,如
com/acme/foo

我正在开发一种JVM语言,其风格要比Java更为独特,因此我将使用其中一种机制,但不能同时使用这两种机制,我想知道应该使用哪种机制


其他JVM语言如Scala和Clojure如何处理它?他们是否需要这两种机制,或者只需要一种机制,如果是这样的话,

< P>我除了Culjueor没有什么经验,但我确实有斯卡拉的经验,Scala也使用子目录作为它们的包,但是其中一个很好的特性是重命名类似C++的TyPuff关键字功能的类。一个有趣的想法是,如果您创建了一个类似于C++的链接器,并允许typedef功能,但仍将其保留在JVM中。

如问题注释中所述是正确的,scalac不会对源文件的路径或名称设置任何此类约束或限制,如果愿意,您甚至可以在一个文件中指定多个包

但是,scalac生成的字节码将字节码类文件放入相应类加载器所需的必要目录结构中。

下面是一些展示灵活性的示例(我不一定提倡这些样式,只是展示了灵活性)

而这个

// in packages2.scala file
package com.foo.bar

sealed trait Scale
case object WebScale extends Scale
case object LolScale extends Scale
case object RoflScale extends Scale
case object WatScale extends Scale
这种风格也是可能的:

// in packages3.scala file
package foo {
  package awesomeness {
    class Main extends App {
      println("Bananas are awesome")
    }
  }
}

package foo {
  package lameness {
    class Main extends App {
      println("Congress is pretty lame, honestly")
    }
  }
}
除了这个

package foo
package bar

// now we are in package foo.bar for remainder of file unless another package statement is made
以下是生成的源代码和编译的字节码树:

$ tree
.
├── com
│   └── foo
│       └── bar
│           ├── LolScale$.class
│           ├── LolScale.class
│           ├── RoflScale$.class
│           ├── RoflScale.class
│           ├── Scale.class
│           ├── WatScale$.class
│           ├── WatScale.class
│           ├── WebScale$.class
│           └── WebScale.class
├── foo
│   ├── awesomeness
│   │   ├── Main$delayedInit$body.class
│   │   └── Main.class
│   └── lameness
│       ├── Main$delayedInit$body.class
│       └── Main.class
├── my
│   └── states
│       ├── CheckingOut$.class
│       ├── CheckingOut.class
│       └── State.class
├── packages1.scala
├── packages2.scala
└── packages3.scala

8 directories, 19 files
我不确定Clojure是否支持这种灵活性,但Clojure的约定是使用Java约定,将源代码结构化到常用的构建工具
lein
(请参阅)

然而,需要注意的一点是,Scala和Clojure中似乎都偏离了Java世界中常用的
$DOMAIN.$APPLICATION
格式(例如
com.oracle.jdbc…
org.hibernate.session…
,等等)。在Scala中,您将看到包名的$DOMAIN部分被完全删除(例如,
scalaz…
akka.{actor,io,…}
,等等)

另外值得注意的是,您可以从Scala中的包导入:

package foo.bar

class Baz{
  private[bar] def boo[A](a: A)
  private[foo] def bla[A](a: A)
}
  • 导入
    foo.bar
    package:
    Import foo.bar.\ucode>
  • 只导入一个类/trait/etc(就像Java一样):
    Import foo.bar.Baz
  • 从包中导入一个类/trait/etc并在当前范围内重命名它:
    Import foo.bar.{Baz=>FooBarBaz}
  • 从包中导入一个子集:
    Import foo.bar.{Baz,Boo,Bla}
另外值得注意的是Scala中的包私有作用域:

package foo.bar

class Baz{
  private[bar] def boo[A](a: A)
  private[foo] def bla[A](a: A)
}
上面的
boo
foo.bar
包(和子包)的私有部分,
bla
foo
及其所有子包的私有部分

有关更多详细信息,请阅读Scala语言规范和相关链接:


    • Clojure有点像Java,但实际上没有类,所以有点不同

      如果存在名称空间project.foo,Clojure编译器将期望在名为foo.clj的文件的源根目录下的项目目录中找到它

      e、 g.假设src是保存源文件的目录。然后project.foo命名空间将位于
      src/project/foo.clj
      中,顶部的声明类似于so
      (ns project.foo)

      我认为很难摆脱这一点,因为在运行时,当Clojure加载文件时(大多数Clojure被捆绑为源代码),Clojure运行时会将文件作为资源加载,这要求它位于目录层次结构中的正确位置(无论是基于jar还是基于文件)


      就个人而言,我也不介意包名==目录位置约定。它使工具在编译或运行时查找文件变得容易,如果我只是使用emacs,也使查找文件变得容易。与目录中的一堆文件相比,它感觉更有条理,尽管这可能更多地取决于我在使用它之后的习惯。

      它们两者都需要,就像Java.interest一样。然后我想另一个问题是:假设他们不需要这两个,你会想把你的源文件放在com/acme/foo中吗?或者,如果您可以将所有源文件直接放入项目的src目录,而不包含子目录,您会更愿意这样做吗?@arshajii:
      scalac
      对路径(或名称)没有任何限制@TravisBrown这是否意味着子目录放置是Scala程序员常用的约定,即使scalac不需要它?@rwallace:是的。您偶尔会在
      src/main/scala/
      下直接找到包含源文件的项目,但下面的Java更常见。