简体   繁体   English

Java包和编译(为什么而不是怎么做)

[英]Java packages and compilation (why, not how)

I'm working on some Java code in eclipse. 我正在使用Eclipse中的一些Java代码。 Code is contained in a single class called Adder , which in Eclipse is in the package org.processing . 代码包含在一个名为Adder类中,该类在Eclipse中位于org.processing包中。 The first thing in the class file is the line 类文件中的第一件事是该行

package org.processing

Q1) What, exactly is this line doing? Q1) 这条线到底在做什么? Why is there, what's it's role. 为什么在那里,它的作用是什么。

The code runs fine in eclipse, however, when I move into the workspace if I go to the src/org/processing/ folder in src , compile with javac Adder.class when I try and run using java Adder I get the following error 该代码运行正常在Eclipse中,但是,当我移动到工作区中,如果我去src/org/processing/文件夹中src ,编译javac Adder.class当我尝试使用运行java Adder ,我得到以下错误

java.lang.NoClassDefFoundError: Adder (wrong name: org/processing/Adder)

On the other hand, if I compile from src using 另一方面,如果我使用src进行编译

javac org/processing/Adder.java

and I can run it from src using java org.processing.Adder but STILL not from within the processing directory. 我可以使用java org.processing.Addersrc运行它,但仍不能从处理目录中运行它。

Q2) Does this mean that compilation is always relative to directory structure? Q2) 这是否意味着编译总是相对于目录结构?

Finally, if I remove the package org.processing line from the start are the .class file I can compile and run from within the .class file's directory. 最后,如果我删除package org.processing从起始行是.class文件我可以编译并从内部运行.class文件的目录。

Q3) Why is all this the way it is? Q3) 为什么一切都是这样? I can fully understand enforcing a directory structure for code development, but once you're in bytecode this seems a bit over the top, because now I can (apparently) only run the bytecode from one director ( src ) using java org.processing.Adder . 我完全理解为代码开发强制执行目录结构,但是一旦您使用字节码,这似乎有点过头了,因为现在(显然)我只能使用java org.processing.Adder从一个Director( src )运行字节码java org.processing.Adder Now, I'm sure I'm missing the point here, so if someone could point out what it is, that would be great. 现在,我确定我在这里没有讲到重点,因此,如果有人可以指出它是什么,那将很棒。

The compiler has to be able to find related source code files when compiling. 编译器在编译时必须能够找到相关的源代码文件。 This is why the package and directory structure must agree for source code. 这就是为什么程序包和目录结构必须同意源代码的原因。 Similarly, the JVM must be able to find referenced .class files. 同样,JVM必须能够找到引用的.class文件。 So the same directory structure is required at runtime. 因此,在运行时需要相同的目录结构。 It's no more complex than that. 没有比这更复杂的了。

Q1) The issue here is that once you got into the folders that represent your package hierarchy, you set that as the working directory. Q1)这里的问题是,一旦进入代表​​程序包层次结构的文件夹,就将其设置为工作目录。 It's gonna look inside of org/processing/Adder for the path org/processing/Adder (essentially looking from the root for org/processing/Adder/org/processing/Adder). 它会在org / processing / Adder内部查找org / processing / Adder路径(实际上是从根目录查找org / processing / Adder / org / processing / Adder)。 You need to call it from the root with the full path. 您需要使用完整路径从根目录调用它。 The purpose of packages is A: to organize related classes into groups. 软件包的目的是:将相关的类分组。 And B: Along with A, classes in package Foo.bar can't view private classes in other packages, as they are like internal classes for that package, only the package they're in can use them 和B:与A一起,软件包Foo.bar中的类无法查看其他软件包中的私有类,因为它们就像该软件包的内部类一样,只有它们所在的软件包才能使用它们

Q2) Yes Q2)

Q3) The paths are used as a basic structure for the JVM to know where exactly the class files (each containing their bytecode) are. Q3)路径用作JVM的基本结构,以了解类文件(每个包含其字节码)的确切位置。 If you change where you call it from, your basically trying to change the location for the JVM to look for the class files, but their true location hasn't changed. 如果更改了调用它的位置,则基本上是尝试更改JVM来查找类文件的位置,但它们的真实位置没有改变。

For Q1: The package declaration allows you to guarantee that your class will never be mistaken for another class with the same name. 对于Q1:包声明使您可以保证您的类永远不会被误认为是另一个具有相同名称的类。 This is why most programmers put their company's name in the package; 这就是为什么大多数程序员将他们公司的名称放在软件包中的原因。 it's unlikely that there will be a conflict. 不太可能出现冲突。

For Q2: There is a one-to-one correspondence between the package structure and the directory structure. 对于Q2:包结构和目录结构之间是一一对应的。 The short of it is that directories and packages must be the same, excepting the package is usually rooted under a folder called src. 简而言之,目录和软件包必须相同,只是软件包通常植根于名为src的文件夹下。

For Q3: Once it's compiled, the class files will probably be in the appropriate folders in a jar file. 对于第三季度:编译完成后,类文件将可能位于jar文件中的相应文件夹中。 Your ant or maven tasks will build the jar file so you won't really have to bother with it beyond getting the ant task set up the first time. 您的ant或maven任务将构建jar文件,因此除了第一次设置ant任务外,您实际上就不必操心它。

The short answer - Packages help keep your project structure well-organized, allow you to reuse names (try having two classes named Account ), and are a general convention for very large projects. 答案很简单- 有助于保持你的项目结构井井有条,让您重用名称(尝试有两班命名Account ),并且是非常大的项目的一般性公约。 They're nothing more than folder structures, but why they're used can burn beginners pretty badly. 它们不过是文件夹结构,但是为什么使用它们会严重烧伤初学者。 Funnily enough, with a project less than 5 classes, you probably won't need it. 有趣的是,对于一个少于5个类的项目, 您可能不需要它。


What, exactly is this line doing? 这行到底在做什么? Why is there, what's it's role. 为什么在那里,它的作用是什么。

The line 线

package org.processing

is telling Java that this class file lives in a folder called /org/processing. 告诉Java此类文件位于名为/ org / processing的文件夹中 This allows you to have a class which is fully defined as org.processing.Processor here, and in another folder - let's say /org/account/processing , you can have a class that's fully defined as org.account.processing.Processor . 这使您可以在这里拥有一个完全定义为org.processing.Processor的类,并在另一个文件夹中-例如/ org / account / processing ,您可以拥有一个完全定义为org.account.processing.Processor Yes, both use the same name, but they won't collide - they're in different packages. 是的,两者都使用相同的名称,但不会冲突-它们位于不同的包装中。 If you do decide to use them in the same class, you would have to be explicit about which one you want to use, either through the use of either import statements or the fully qualified object name. 如果确实决定在同一个类中使用它们,则必须通过使用import语句或完全限定的对象名称来明确说明要使用哪个类。

Does this mean that compilation is always relative to directory structure? 这是否意味着编译总是相对于目录结构?

Yes. 是。 Java and most other languages have a concept known as a classpath . Java和大多数其他语言都有一个称为类路径的概念。 Anything on this classpath can be compiled and run, and by default, the current directory you're in is on the classpath for compilation and execution. 可以编译和运行此类路径上的所有内容,默认情况下,您所在的当前目录位于该类路径上,用于编译和执行。 To place other files on the classpath, you would have to use another command-line invocation to your compilation: 要将其他文件放在类路径中,您将必须对编译使用另一个命令行调用:

javac -sourcepath /path/to/source MainClass.java

...and this would compile everything in your source path to your current directory, neatly organized in the folder structure specified by your package statements. ...这会将源路径中的所有内容编译到当前目录,并按package语句指定的文件夹结构整齐地组织起来。

To run them, as you've already established, you would need to include the compiled source in your classpath, and then execute via the fully qualified object name : 要运行它们,就像已经建立的一样,您需要在类路径中包含已编译的源代码,然后通过完全限定的对象名执行:

java -cp /path/to/source org.main.MainClass

Why is all this the way it is? 为什么这一切都是这样?

Like I said before, this is mostly useful for very large projects , or projects that involve a lot of other classes and demand structure/organization, such as Android. 就像我之前说过的,这对于大型项目或涉及许多其他类和需求结构/组织的项目(例如Android)最有用。 It does a few things: 它做一些事情:

  • It keeps source organized in an easy-to-locate structure. 它以易于查找的结构来组织源代码。 You don't have objects scattered all over the place. 您不会在整个地方散落物体。
  • It keeps the scope of your objects clear. 它使您的对象范围保持清晰。 If I had a package named org.music.db , then it's pretty clear that I'm messing with objects that deal with the database and persistence. 如果我有一个名为org.music.db的程序包,那么很显然我正在搞乱处理数据库和持久性的对象。 If I had a package named org.music.gui , then it's clear that this package deals with the presentation side. 如果我有一个名为org.music.gui的程序包,那么很显然,该程序包用于表示方面。 This can help when you want to create a new feature, or update/refactor an existing one; 当您要创建新功能或更新/重构现有功能时,这可以提供帮助。 you can remember what it does , but you can't recall its name exactly. 您可以记住它的功能 ,但不能确切地记住它的名称
  • It allows you to have objects with the same name. 它允许您具有相同名称的对象。 There is more than one type of Map out there, and if you're using projects that pull that in, you'd want to be able to specify which Map you get - again, accomplished through either imports or the fully qualified object name. 有多种类型的Map ,如果您使用的是将Map引入其中的项目,则希望能够指定要获取的Map又可以通过导入或完全限定的对象名称来完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM