为新手解释Java项目结构?
我来自.NET背景,对于Java来说是全新的,并且正试图让我的头脑围绕Java项目结构。
我典型的.NET解决scheme结构包含的项目表示逻辑上不同的组件,通常使用以下格式命名:
MyCompany.SomeApplication.ProjectName
项目名称通常等于项目的根名称空间。 如果它是一个大项目,我可能会进一步分解命名空间,但是更多的时候我看不到任何进一步的命名空间。
现在在Java中,你有应用程序组成的项目,然后你有一个新的逻辑层次 – 包。 什么是包裹? 它应该包含什么? 你在这个App.Project.Package
结构中如何命名空间? JAR在哪里适合这一切? 基本上,有人可以提供一个Java应用程序结构的新手介绍?
谢谢!
编辑:一些真正的破解答案谢谢你们。 随后几个后续问题:
- .JAR文件是否包含编译好的代码? 或只是压缩的源代码文件?
- 包名是否都是小写字母有充分的理由吗?
- 包可以有“循环依赖”? 换句话说,Package.A可以使用Package.B,反之亦然?
- 任何人都可以显示声明一个类的典型语法是在一个包中,并声明你希望引用另一个包在一个类中(一个using语句也许?)
“简单”的J2SE项目
正如Cletus所解释的那样,源目录结构直接等同于包结构,并且基本上内置于Java中。 其他一切都不太清楚。
很多简单的项目都是通过手工组织的,所以人们可以select一个他们感觉良好的结构。 通常做的事情(这也反映在Eclipse中一个非常占优势的Java工具的项目结构上)是让源码树在一个名为src
的目录中开始。 你的无包文件源文件将直接放在src中,你的包层次结构(通常以com
目录开头)同样包含在src
。 如果在启动javac
编译器之前将CD
放入src
目录中,则编译后的.class
文件将以相同的目录结构结束,每个.class文件位于相同的目录中,并位于.java
文件旁边。
如果你有很多的源文件和类文件,你需要把它们分开,以减less混乱。 手动和Eclipse组织通常将一个bin
或者classes
目录放到src
这样.class文件就会以一个反映src
的层次结构。
如果您的项目有一组.jar
文件来提供第三方库的function,那么第三个目录(通常是lib
)将与src
和bin
并行放置。 lib
所有东西都需要放在classpath中进行编译和执行。
最后,还有一些这个或多或less是可选的:
- doc中的
doc
-
resources
- 数据中的
data
- configuration在
conf
…
你明白了。 编译器不关心这些目录,它们只是你自己组织(或混淆)的方法。
J2EE项目
J2EE大致相当于ASP.NET,这是一个组织Web应用程序的巨大(标准)框架。 虽然你可以用任何你喜欢的方式开发你的J2EE项目代码,但是Web容器将会期望你的应用程序提交的结构有一个坚实的标准。而且这个结构也会反映到源代码布局中。 下面是一个详细介绍Java项目的项目结构的页面(他们与我上面写的不一致),特别是J2EE项目:
http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html
Maven项目
Maven
是一个非常灵活的项目构build工具。 就我个人而言,我的构build需求很好地被ant
满足,这大致与nmake
。 另一方面,Maven是一个完整的生命周期pipe理系统,依赖pipe理已经被大量使用。 Java世界中的大部分代码的库和源代码在“net”中是免费的,如果问得好的话,maven将会为你抓取它,并且把你的项目需要的东西带回家,甚至不需要你去告诉它。 它也为你pipe理一个小库。
这个高度勤劳的小动物的缺点是,这是一个项目结构高度法西斯的事实。 你做Maven的方式,或根本没有。 通过强迫自己的标准落到实处,Maven设法使全球的项目在结构上更加相似,更易于pipe理,并且以最less的投入自动构build。
如果你selectMaven,你可以停止担心项目结构,因为只能有一个。 这是它: http : //maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html
Java中的包与.NET中的名称空间非常相似。 包的名字本质上是创build一个到它里面的类的path。 这个path可以被认为是类的名字空间(用.Net术语来说),因为它是你要使用的特定类的唯一标识符。 例如,如果您有一个名为:
org.myapp.myProject
在里面你有一堆课:
MyClass1 MyClass2
要特别指出您将使用的那些类:
org.myapp.myProject.MyClass1 org.myapp.myProject.MyClass2
这和.Net(我知道)之间唯一真正的区别是,Java在结构上组织它的“命名空间”(每个包是一个独立的文件夹),而.Net允许你使用namespace
关键字来限定类,并忽略文档的实际位置住。
在大多数情况下,JAR文件大致类似于DLL。 这是一个压缩文件(可以用7zip打开)包含其他项目的源代码,这些项目可以在应用程序中作为依赖项添加。 库通常包含在JAR中。
关于Java的事情要记住的是非常结构化的; WHERE文件的存在很重要。 当然,还有更多的故事,然后我发布,但我认为这应该让你开始。
一个包很像.Net命名空间。 在Java中的一般惯例是使用反向域名作为包前缀,所以如果你的公司是example.com,你的包可能是:
com.example.projectname.etc...
它可以分解成许多层次,而不仅仅是一个(项目名称),但通常是足够的。
在你的项目结构中,类通常被分成逻辑区域:控制器,模型,视图等等。这取决于项目的types。
Java中有两个主要的构build系统:Ant和Maven。
Ant基本上是一个特定于领域的脚本语言,并且非常灵活,但是最终你自己写了很多样板文件(构build,部署,testing等等)。 这虽然快捷方便。
Maven更现代,更完整,值得使用(imho)。 Maven与Ant的不同之处在于Maven声明这个项目是一个“Web应用程序项目”(称为原型 )。 一旦声明了,一旦你指定了groupId(com.example)和artifactId(项目名称),目录结构就被强制执行了。
这样可以免费得到很多东西。 Maven的真正好处在于它可以通过一个pom.xml(Maven项目文件)来pipe理你的项目依赖关系,并且正确configurationMaven,你可以把它交给别人(用你的源代码),并且可以构build,部署,testing并自动下载库来运行你的项目。
ant常春藤得到这样的东西。
下面是关于Java包的一些注意事项,应该让你开始:
Java软件包名称的最佳做法是使用组织的域名作为软件包的开始,反之,例如,如果您的公司拥有域名“bobswidgets.com”,则可以使用“com”来启动软件包。 bobswidgets”。
下一个级别通常是应用程序或库级别,所以如果是电子商务库,则可能是“com.bobswidgets.ecommerce”。
进一步比这往往代表了你的应用程序的体系结构。 作为项目核心的类和接口驻留在“root”中,例如com.bobswidgets.ecommerce.InvalidRequestException。
使用包进一步细分function是很常见的。 通常这种模式是将接口和exception放到细分的根部,并将其实现到子包中
com.bobswidgets.ecommerce.payment.PaymentAuthoriser (interface) com.bobswidgets.ecommerce.payment.PaymentException com.bobswidgets.ecommerce.payment.paypal.PaypalPaymentAuthoriser (implementation)
这使得将“付款”类和包放入他们自己的项目中变得非常容易。
其他一些说明:
Java包与目录结构紧密耦合。 因此,在一个项目中,一个包含com.example.MyClass的类将永远在com / example / MyClass.java中。 这是因为当它被打包成一个Jar时,类文件肯定会在com / example / MyClass.class中。
Java包与项目松散耦合。 项目将拥有自己独特的软件包名称是很常见的,例如com.bobswidgets.ecommerce for ecommerce,com.bobswidgets.intranet for intranet project。
Jar文件将容器编译你的.java代码成字节码的结果的类文件。 他们只是扩展名为.jar的zip文件。 Jar文件的根目录是命名空间层次结构的根目录,例如com.bobswidgets.ecommerce将在Jar文件中为/ com / bobswidgets / ecommerce /。 Jar文件也可以容器资源,例如属性文件等
一个包是一组源文件,可以让他们看到对方的包 – 私有方法和variables,以便这组类可以访问其他类不能访问的东西。
期望的是所有的java类都有一个用来消除歧义的包。 所以如果你在你的项目中打开一个jar文件,比如spring,那么每个包都以org.springframework开始。 类加载器不知道jarfile名称,他们只使用包。
按照对象或function的types来分解东西是一种普遍的做法,并不是每个人都同意这一点。 就像在这里发布的Cletus一样,将Web控制器,域对象,服务和数据访问对象分组到他们自己的包中是一种趋势。 我认为一些领域驱动devise人员不认为这是一件好事。 它的优势在于,通常包中的所有内容都具有相同的依赖关系(控制器可能依赖于服务和域对象,服务依赖于域对象和数据访问对象等),因此可以很方便。
好的,所以在Java中,你有三种不同types的类成员函数和variables的访问
公共保护包 – 私人和私人
同一个包中的所有类都可以看到其他公共,受保护和包私有的元素。
包在系统中不是分层的。 通常它们是以分层的方式组织的,但就运行时而言,com.example.widgets是一个与com.example.widgets.cogs完全不同的包
包被安排为目录,这有助于保持组织结构:文件结构总是与包结构相似。
他们正在计划在JDK7中为Java添加一个模块系统(称为Project Jigsaw ),并且存在一个名为OSGi的现有模块系统。 这些模块系统将为您提供更多的灵活性和function,然后是简单的包系统。
而且,软件包名称通常都是小写字母。 🙂
维基百科:
Java包是一种将Java类组织到名称空间中的机制
和
Java包可以存储在称为JAR文件的压缩文件中
所以对于包abc,你可以在a,ab和abc包中包含Java类。 通常,当它们表示相关的function时,它们将同一个包中的类分组。 在function上,同一个包中的类和不同包中的类之间的唯一区别在于,Java中成员的默认访问级别是“包保护”的,这意味着同一包中的其他类可以访问。
对于类abcMyClass,如果你想在你的项目中使用MyClass,你可以import abcMyClass
或者不推荐使用import abc*
另外,MyClass首先驻留在包abc中,你可以在MyClass的第一行声明它.java: package abc;
。
要做到这一点,你可以JAR整个包(包括包B和C和类MyClass),并把这个JAR到你的$CLASSPATH
; 这将使您的其他源代码可以使用(通过上述导入语句)。
回答这个例子子问题:
package com.smotricz.goodfornaught; import java.util.HashMap; import javax.swing.*; public class MyFrame extends JFrame { private HashMap myMap = new HashMap(); public MyFrame() { setTitle("My very own frame"); } }
.JAR文件是否包含编译好的代码? 或只是压缩的源代码文件?
它们可能包含两种,甚至完全不同的文件,如图片。 首先是一个zip文件。 大多数情况下,您会看到包含类文件的JAR以及包含源文件(如果您使用第三方代码时在IDE中进行debugging便利)或包含javadoc(源代码documentatin)的JAR,如果IDE支持对文档进行工具提示当你访问lib的函数。
包名是否都是小写字母有充分的理由吗?
是的,软件包名称用小写字母写有一个很好的理由:有一个指导说,只有类名是用大写字母写在前面。
包可以有“循环依赖”? 换句话说,Package.A可以使用Package.B,反之亦然?
包不互相使用。 只有class才能做到。 是的,这可能是可能的,但不好的做法。
任何人都可以显示声明一个类的典型语法是在一个包中,并声明你希望引用另一个包在一个类中(一个using语句也许?)
假设您想要使用java.util包中的ArrayList类,请使用
import java.util.ArrayList; ArrayList myList = new ArrayList();
或者在没有导入的情况下使用(比如说你使用了两个不同的包,
java.util.ArrayList myList = new java.util.ArrayList(); your.package.ArrayList mySecondList = new your.package.ArrayList();
虽然循环依赖类并不是一件容易的事情,但也不是不可能的。 我确实得到它在一个案件的工作。 A类和B类彼此依赖,不会从头开始编译。 但是认识到A类的一部分不需要B类,那部分是B类需要完全编译的,我把A类的那部分,B类不需要的部分,剩下的部分类A能够编译,然后我能够编译B类。然后,我可以解除需要B类的A类部分,并且能够编译完整的类A.这两个类都可以正常工作。 虽然这不是典型的,但是如果这些class级像这样连在一起的话,那就是犹太教,有时可能是必要的。 只要确保你留下自己特殊的编译指示,以便将来的更新。