简体   繁体   English

Java:编译器和JRE是否需要访问所有第三方类文件?

[英]Java: Do BOTH the compiler AND the JRE require access to all 3rd-party class files?

I have 15 years' C++ experience but am new to Java. 我有15年的C ++经验,但我不熟悉Java。 I am trying to understand how the absence of header files is handled by Java. 我试图了解Java如何处理头文件的缺失。 I have a few questions related to this issue. 我有几个与此问题相关的问题。

Specifically, suppose that I write source code for a class 'A' that imports a 3rd-party class 'Z' (and uses Z). 具体来说,假设我为导入第三方类'Z'(并使用Z)的类'A'编写源代码。 I understand that at compile-time, the Java compiler must have "access" to the information about Z in order to compile A.java, creating A.class. 据我所知,在编译时,Java编译器必须“访问”有关Z的信息才能编译A.java,创建A.class。 Therefore, either Z.java or Z.class (or a JAR containing one of these; say Z.jar) must be present on the local filesystem at compile time - correct? 因此,Z.java或Z.class(或包含其中一个的JAR;比如Z.jar)必须在编译时出现在本地文件系统上 - 对吗?

Does the compiler use a class loader to load Z (to reiterate - at compile time)? 编译器是否使用类加载器加载Z(重复 - 在编译时)?

If I'm correct that a class loader is used at COMPILE time, what if a user-defined class loader (L) is desired - and is part of the project being compiled? 如果我在COMPILE时使用类加载器是正确的,那么如果需要用户定义的类加载器(L)并且是正在编译的项目的一部分呢? Suppose, for example, that L is responsible for downloading Z.class AT RUNTIME across a network? 例如,假设L负责通过网络下载Z.class AT RUNTIME? In this scenario, how will the Java compiler obtain Z.class at compile time? 在这种情况下,Java编译器将如何在编译时获取Z.class? Will it attempt to compile L first, and then use L at compile time to obtain Z? 它会先尝试编译L,然后在编译时使用L来获取Z吗?

I understand that using Maven to build the project, Z.jar can be located on a remote repository over the internet at compile time - either on ibiblio, or on a custom repository defined in the POM file. 据我所知,使用Maven构建项目,Z.jar可以在编译时通过Internet定位在远程存储库中 - 在ibiblio上,或在POM文件中定义的自定义存储库中。 I hope I'm correct that it is MAVEN that is responsible for downloading the 3rd-party JAR file at compile time, rather than the compiler's JVM? 我希望我是正确的,它是MAVEN负责在编译时下载第三方JAR文件,而不是编译器的JVM?

Note, however, that at RUNTIME, A.class again requires Z.class - how will JRE know where to download Z.class from (without Maven to help)? 但请注意,在RUNTIME,A.class再次需要Z.class - JRE将如何知道从哪里下载Z.class(没有Maven帮助)? Or is it the developer's responsibility to ship Z.class along with A.class with the application (say in the JAR file)? 或者开发人员有责任将Z.class与A.class一起发布到应用程序(例如在JAR文件中)? (...assuming a user-defined class loader is not used.) (...假设未使​​用用户定义的类加载器。)

Now a related question, just for confirmation: I assume that once compiled, A.class contains only symbolic links to Z.class - the bytecodes of Z.class are not part of A.class; 现在一个相关的问题,只是为了确认:我假设一旦编译,A.class只包含到Z.class的符号链接 - Z.class的字节码不是A.class的一部分; please correct me if I'm wrong. 如果我错了,请纠正我。 (In C++, static linking would copy the bytes from Z.class into A.class, whereas dynamic linking would not.) (在C ++中,静态链接会将字节从Z.class复制到A.class中,而动态链接则不会。)

Another related question regarding the compilation process: once the necessary files describing Z are located on the CLASSPATH at compile time, does the compiler require the bytecodes from Z.class in order to compile A.java (and will build Z.class, if necessary, from Z.java), or does Z.java suffice for the compiler? 关于编译过程的另一个相关问题:一旦描述Z的必要文件在编译时位于CLASSPATH上,编译器是否需要Z.class中的字节码才能编译A.java(如果需要,将构建Z.class) ,来自Z.java),还是Z.java足以满足编译器的需要?

My overall confusion can be summarized as follows. 我的整体困惑可归纳如下。 It seems that the full [byte]code for Z needs to be present TWICE - once during compilation, and a second time during runtime - and that this must be true for ALL classes referenced by a Java program. 似乎Z的完整[byte]代码需要存在TWICE - 一次在编译期间,第二次在运行时 - 并且对于Java程序引用的所有类必须为true。 In other words, every single class must be downloaded/present TWICE. 换句话说,每个类必须下载/呈现TWICE。 Not a single class can be represented during compile time as just a header file (as it can be in C++). 在编译期间,不能将单个类表示为头文件(因为它可以在C ++中)。

Does the compiler use a class loader to load Z (to reiterate - at compile time)? 编译器是否使用类加载器加载Z(重复 - 在编译时)?

Almost. 几乎。 It uses a JavaFileManager which acts like a class loader in many ways. 它使用JavaFileManager ,它在很多方面充当类加载器。 It does not actually load classes though since it needs to create class signatures from .java files as well as .class files. 它实际上并没有加载类,因为它需要从.java文件和.class文件创建类签名。

I hope I'm correct that it is MAVEN that is responsible for downloading the 3rd-party JAR file at compile time, rather than the compiler's JVM? 我希望我是正确的,它是MAVEN负责在编译时下载第三方JAR文件,而不是编译器的JVM?

Yes, Maven pulls down jars, although it is possible to implement a JavaFileManager that behaves like a URLClassLoader . 是的,虽然可以实现一个行为类似于URLClassLoader的JavaFileManager,但是Maven可以下载jar。 Maven manages a local cache of jars, and will fill that cache from the network as needed. Maven管理jar的本地缓存,并根据需要从网络填充缓存。

Another related question regarding the compilation process: once the necessary files describing Z are located on the CLASSPATH at compile time, does the compiler require the bytecodes from Z.class in order to compile A.java (and will build Z.class, if necessary, from Z.java), or does Z.java suffice for the compiler? 关于编译过程的另一个相关问题:一旦描述Z的必要文件在编译时位于CLASSPATH上,编译器是否需要Z.class中的字节码才能编译A.java(如果需要,将构建Z.class) ,来自Z.java),还是Z.java足以满足编译器的需要?

It does not require all bytecode. 它不需要所有字节码。 Just class, method, and property signatures and metadata. 只是类,方法和属性签名和元数据。 If A depends on Z, that dependency can be satisfied by a Z.java found on the source path, on a Z.class found on any of the (class path, system class path), or via some custom extension like a Z.jsp. 如果A依赖于Z,则可以通过在源路径上找到的Z.java,在任何(类路径,系统类路径)上找到的Z.class或通过某些自定义扩展(如Z)来满足该依赖关系。 JSP。

My overall confusion can be summarized as follows. 我的整体困惑可归纳如下。 It seems that the full [byte]code for Z needs to be present TWICE - once during compilation, and a second time during runtime - and that this must be true for ALL classes referenced by a Java program. 似乎Z的完整[byte]代码需要存在TWICE - 一次在编译期间,第二次在运行时 - 并且对于Java程序引用的所有类必须为true。 In other words, every single class must be downloaded/present TWICE. 换句话说,每个类必须下载/呈现TWICE。 Not a single class can be represented during compile time as just a header file (as it can be in C++). 在编译期间,不能将单个类表示为头文件(因为它可以在C ++中)。

Maybe an example can help clear this up. 也许一个例子可以帮助澄清这一点。 The java language specification requires the compiler do certain optimizations. java语言规范要求编译器进行某些优化。 Inlining of static final primtives and String s. 内联static final原始StringString

If class A depends on B only for a constant: 如果A类仅依赖于B作为常数:

class B {
  public static final String FOO = "foo";
}

class A {
  A() { System.out.println(B.FOO); }
}

then A can be compiled, loaded, and instantiated without B.class on the classpath. 然后可以在类路径上编译,加载和实例化A而不使用B.class If you changed and shipped a B.class with a different value of FOO then A would still have that compile time dependency. 如果您更改并发送了具有不同FOO值的B.class ,则A仍将具有该编译时依赖性。

So it is possible to have a compile-time dependency and not a link-time dependency. 因此,可以具有编译时依赖性而不是链接时依赖性。

It is, of course, possible to have a runtime dependency without a compile-time dependency via reflection. 当然,通过反射可以获得没有编译时依赖性的运行时依赖性。

To summarize, at compile time, the compiler makes sure that the methods and properties a class accesses are available. 总而言之,在编译时,编译器确保类访问的方法和属性可用。

At class load time (runtime) the byte-code verifier checks that the expected methods and properties are really there. 在类加载时(运行时),字节码验证器检查预期的方法和属性是否真的存在。 So the byte-code verifier double checks the assumptions the compiler makes (except for inlining assumptions such as those above). 因此,字节码验证器会仔细检查编译器所做的假设(内联假设除外)。

It is possible to blur these distinctions. 可以模糊这些区别。 Eg JSP uses a custom classloader that invokes the java compiler to compile and load classes from source as needed at runtime. 例如,JSP使用一个自定义类加载器来调用java编译器,以便在运行时根据需要从源代码编译和加载类。

The best way to understand how Maven fits into the picture is to realize that it (mostly) doesn't. 理解Maven如何适应图片的最好方法是意识到它(大部分)没有。

Maven is NOT INVOLVED in the processes by which the compiler finds definitions, or the runtime system loads classes. Maven不参与编译器查找定义的过程,或者运行时系统加载类。 The compiler does this by itself ... based on what the build-time classpath says. 编译器本身就是这样做的...基于构建时类路径所说的内容。 By the time that you run the application, Maven is no longer in the picture at all. 当您运行该应用程序时,Maven根本不再处于图片中。

At build time, Maven's role is to examine the project dependencies declared in the POM files, check versions, download missing projects, put the JARs in a well known place and create a "classpath" for the compiler (and other tools) to use. 在构建时,Maven的作用是检查在POM文件中声明的项目依赖项,检查版本,下载缺少的项目,将JAR放在一个众所周知的位置,并为编译器(和其他工具)创建一个“类路径”。

The compiler then "loads" the classes that it needs from those JAR files to extract type signature information in the compiled class files. 然后,编译器从这些JAR文件中“加载”它所需的类,以在已编译的类文件中提取类型签名信息。 It doesn't use a regular class loader to do this, but the basic algorithm for locating the classes is the same. 它不使用常规类加载器来执行此操作,但用于查找类的基本算法是相同的。

Once the compiler has done, Maven then takes care of packaging into JAR, WAR, EAR files and so on, as specified by the POM file(s). 编译完成后,Maven会负责打包到JAR,WAR,EAR文件等,这些都是由POM文件指定的。 In the case of a WAR or EAR file, all of the required dependent JARs packaged into the file. 对于WAR或EAR文件,将所有必需的从属JAR打包到文件中。

No Maven-directed JAR downloading takes place at runtime. 没有Maven导向的JAR下载在运行时发生。 However, it is possible that running the application could involve downloading JAR files; 但是,运行应用程序可能涉及下载JAR文件; eg if the application is deployed using Java WebStart. 例如,如果使用Java WebStart部署应用程序。 (But the JARs won't be downloaded from a Maven repository in this case ...) (但在这种情况下,JAR不会从Maven存储库下载...)

Some more things to note: 还有一些事情需要注意:

  • Maven does not need to be in the picture at all. Maven根本不需要在图片中。 You could use an IDE to do the building, the Ant build tool (maybe with Ivy), Make or even "dumb" shell scripts. 您可以使用IDE来构建构建,Ant构建工具(可能是Ivy),Make甚至是“哑”shell脚本。 Depending on the build mechanism, you may need to handle external dependencies by hand; 根据构建机制,您可能需要手动处理外部依赖项; eg figuring out with external JARs to download, where to put them and so on. 例如,找出外部JAR下载,放置它们等等。

  • The Java runtime system typically has to load more than the compiler does. Java运行时系统通常必须加载比编译器更多的内容。 The compiler only needs to load those classes that are necessary to type-check the classes that are being compiled. 编译器只需要加载那些类型检查正在编译的类所必需的类。

    For example, suppose class A has a method that uses class B as a parameter, and class B has a method that uses class C as a parameter. 例如,假设类A有一个使用类B作为参数的方法,而类B有一个使用类C作为参数的方法。 When compiling A , B needs to be loaded, but not C (unless A directly depends on C in some way). 在编译A ,需要加载B ,而不是C (除非A在某种程度上直接依赖于C )。 When executing A , both B and C needs to be loaded. 执行A ,需要加载BC

    A second example, suppose that class A depends on interface I with implementations IC1 and IC2 . 第二个例子,假设A类依赖于接口I和实现IC1IC2 Unless A explicitly depends on IC1 or IC2 , the compiler does not need to load them to compile A . 除非A明确依赖于IC1IC2 ,否则编译器不需要加载它们来编译A

  • It is also possible to dynamically load classes at runtime; 也可以在运行时动态加载类; eg by calling Class.forName(className) where className is a string-valued expression. 例如,通过调用Class.forName(className) ,其中className是一个字符串值表达式。


You wrote: 你写了:

For the example in your second bullet point - I'd think that the developer could choose to provide, at compile time, a stub file for B that does not include B's method that uses C, and A would compile just fine. 对于第二个要点中的示例 - 我认为开发人员可以选择在编译时为B提供一个不包含使用C的B方法的存根文件,并且A可以编译得很好。 This would confirm my assessment that, at compile time, what might be called "header" files with only the necessary functions declared (even as stubs) is perfectly allowed in Java - so it's just for convenience/convention that tools have evolved over time not to use a header/source file distinction. 这将证实我的评估,在编译时,在Java中完全允许所谓的“头”文件,其中只声明了必要的函数(即使是存根) - 所以这只是为了方便/约定,工具随着时间的推移不再发展使用标头/源文件区分。 (Correct me if I'm wrong.) (如我错了请纠正我。)

It is not a convenience / evolutionary thing. 它不是一个方便/进化的东西。 Java has NEVER supported separate header files. Java从未支持单独的头文件。 James Gosling et al started from the position that header files and preprocessors were a bad idea. 詹姆斯·戈斯林等人从头文件和预处理器是一个坏主意的立场开始。

Your hypothetical stub version of B would have to have all of the visible methods, constructors and fields of the real B , and the methods and constructors would have to have bodies. 你假设的B版存根版必须拥有真实B所有可见方法,构造函数和字段,并且方法和构造函数必须具有实体。 The stub B wouldn't compile otherwise. 存根B不会编译。 (I guess in theory, the bodies could be empty, return a dummy value or throw an unchecked exception.) (我猜在理论上,主体可能是空的,返回虚拟值或抛出未经检查的异常。)

The problem with this approach is that it would be horribly fragile . 这种方法的问题在于它会非常脆弱 If you made the smallest mistake in keeping the stub and full versions of B in step, the result would be that the class loader (at runtime) would report a fatal error. 如果您在保持的存根和完整版本做出的最小的错误B步骤,其结果必然是类装载器(在运行时)会报告一个致命的错误。

By the way, C and C++ are pretty much the exception in having separate header files. 顺便说一句,C和C ++几乎是拥有单独头文件的例外。 In most other languages that support separate compilation (of different files comprising an application), the compiler can extract the interface information (eg signatures) from the implementation source code. 在支持单独编译的大多数其他语言中(包括应用程序的不同文件),编译器可以从实现源代码中提取接口信息(例如,签名)。

One other piece to the puzzle which may help, interfaces and abstract classes are compiled to class files as well. 另外一个可以帮助的拼图,接口和抽象类也被编译成类文件。 So when compiling A, ideally you would be compiling against the API and not necessarily the concrete class. 因此,在编译A时,理想情况下,您将针对API进行编译,而不一定是具体类。 So if A uses interface B (which is implemented by Z) at compile time you would need classfiles for A & B but at runtime you would need class files for A, B and Z. You are correct that all classes are dynamically linked (You can crack the files and look at the bytecode and see the fully qualified names in there. jclasslib is an excellent utility for inspecting class files and reading bytecode if you're curious). 因此,如果A在编译时使用接口B(由Z实现),则需要A和B的类文件,但在运行时,您需要A,B和Z的类文件。所有类都是动态链接的(正确的)可以破解文件并查看字节码并查看其中的完全限定名称。如果你很好奇, jclasslib是一个很好的检查类文件和读取字节码的工具。 I can replace classes at runtime. 我可以在运行时替换类。 But problems at runtime often result in various forms of LinkageErrors 但是运行时的问题通常会导致各种形式的LinkageErrors

Often the decision on should a class be shipped with your compiled jar files, depends on your particular scenario. 通常,如果一个类与您编译的jar文件一起发布,则决定取决于您的特定方案。 There are classes that are assumed to be available in every JRE implementation. 假定在每个JRE实现中都有可用的类。 But if I have my own API and implementation I would have to somehow provide both to wherever they are run. 但是,如果我有自己的API和实现,我将不得不以某种方式提供它们运行的​​任何地方。 There are some APIs though, for example servlets where I would compile against the servlet API, but the container (eg Websphere) is responsible for providing the servlet API and implementation at runtime for me (therefore I shouldn't ship my own copies of these). 有一些API尽管例如servlet的 ,我会针对编译该servlet API,但容器(例如的Websphere)负责提供该servlet API和实现在运行时,我(因此我不应该出货我自己的这些副本)。

I have 15 years' C++ experience but am new to Java. 我有15年的C ++经验,但我不熟悉Java。

The biggest challenge you are likely to face is that many things which are treated as important in C++, such as the sizeof() an object, unsigned integers and destructors, are not easy to do in Java and are not treated with the same importance and have other solutions/work arounds. 您可能面临的最大挑战是许多在C ++中被视为重要的东西,例如sizeof()一个对象,无符号整数和析构函数,在Java中并不容易做到,并且没有被视为具有相同的重要性和有其他解决方案/解决方案。

I am trying to understand how the absence of header files is handled by Java. 我试图了解Java如何处理头文件的缺失。 I have a few questions related to this issue. 我有几个与此问题相关的问题。

Java has interfaces which are similar in concept to header files in the sense that they contain only declarations (and constants) without definitions. Java有一些概念与头文件类似的接口,因为它们只包含没有定义的声明(和常量)。 Classes are often paired with an interface for that class, sometimes one to one. 类通常与该类的接口配对,有时一对一。

Does the compiler use a class loader to load Z (to reiterate - at compile time)? 编译器是否使用类加载器加载Z(重复 - 在编译时)?

When a class loader loads a class, it calls the static initialisation block, which can do just about anything. 当类加载器加载一个类时,它会调用静态初始化块,它可以执行任何操作。 All the compiler needs is to extract meta-data from the class, not the byte code and this is what it does. 所有编译器需要的是从类中提取元数据,而不是字节代码,这就是它的作用。

it is MAVEN that is responsible for downloading the 3rd-party JAR file at compile time, rather than the compiler's JVM? 是MAVEN负责在编译时下载第三方JAR文件,而不是编译器的JVM?

Maven must load the file to a local filesystem, the default locations is ~/.m2/repository Maven必须将文件加载到本地文件系统,默认位置为~/.m2/repository

how will JRE know where to download Z.class from (without Maven to help)? JRE如何知道从哪里下载Z.class(没有Maven帮助)?

Its must either use Maven; 它必须要么使用Maven; Some OSGi containers are able to load and unload different versions dynamically, for example you can change the version of a library in a running system, or update a SNAPSHOT from a maven build. 一些OSGi容器能够动态加载和卸载不同的版本,例如,您可以在正在运行的系统中更改库的版本,或从maven构建更新SNAPSHOT。

Or you have a stand alone application; 或者你有一个独立的应用程序; Using a Maven plugin like appassembly you can create batch/shell script and a directory with a copy of all the libraries you need. 使用像appassembly这样的Maven插件,您可以创建批处理/ shell脚本以及包含所需库的副本的目录。

Or a web archive war which contains meta informations and many jars inside it. 或者是一个包含元信息和其中的许多jar的web存档war (It just a jar containing jars ;) (它只是一个装有罐子的罐子;)

Or is it the developer's responsibility to ship Z.class along with A.class with the application 或者,开发人员有责任将Z.class与A.class一起发布到应用程序中

For a standalone application yes. 对于独立应用程序是。

Now a related question, just for confirmation: I assume that once compiled, A.class contains only symbolic links to Z.class 现在是一个相关的问题,仅供确认:我假设一旦编译,A.class只包含指向Z.class的符号链接

Technically, it only contains strings with Z in them, not the .class itself. 从技术上讲,它只包含带有Z字符串,而不包含.class本身。 You can change alot of the Z without compiling A again and it will still work. 你可以改变很多Z而不再编译A,它仍然可以工作。 eg you might compile against once version of Z and replace it with another version later and the application can still run. 例如,你可以编译一次版本的Z并稍后用另一个版本替换它,应用程序仍然可以运行。 You can even replace it while the application is running. 您甚至可以在应用程序运行时替换它。 ;) ;)

the bytecodes of Z.class are not part of A.class; Z.class的字节码不是A.class的一部分;

The compiler does next to no optimisations. 编译器旁边没有优化。 The only significant one IMHO, is that it inlines compile time constants. 唯一重要的一个是IMHO,它是内联编译时常量。 This means if you change a constant in Z after compiling A it may not change in A. (If you make the constant not known at compile time it won't inline it) 这意味着如果在编译A后更改Z中的常量,则在A中可能不会更改。(如果在编译时使常量未知,则不会内联它)

No byte-code is inlined, native code from the byte code is inlined at at runtime based on how the program actually runs. 没有内联字节代码,字节代码中的本机代码在运行时根据程序实际运行的方式进行内联。 eg say you have a virtual methods with N implementations. 例如,假设您有一个具有N个实现的虚拟方法。 A C++ compiler wouldn't know which ones to inline esp as they might not be available at compile time. C ++编译器不知道哪些内联esp,因为它们在编译时可能不可用。 However the JVM can see which ones are used the most (it collects stats as the program runs) and can inline the two most commonly used implementations. 但是,JVM可以看到哪些是最常用的(它在程序运行时收集统计信息)并且可以内联两个最常用的实现。 (Food for thought as to what happens when you remove/update one of those classes at runtime ;) (关于在运行时删除/更新其中一个类时会发生什么的思考的食物;)

please correct me if I'm wrong. 如果我错了,请纠正我。 (In C++, static linking would copy the bytes from Z.class into A.class, whereas dynamic linking would not.) (在C ++中,静态链接会将字节从Z.class复制到A.class中,而动态链接则不会。)

Java has only dynamic linking but this doesn't prevent inlining of code at runtime which is as efficient as using a macro. Java只有动态链接,但这并不妨碍在运行时内联代码,这与使用宏一样有效。

Another related question regarding the compilation process: once the necessary files describing Z are located on the CLASSPATH at compile time, does the compiler require the bytecodes from Z.class in order to compile A.java (and will build Z.class, if necessary, from Z.java), or does Z.java suffice for the compiler? 关于编译过程的另一个相关问题:一旦描述Z的必要文件在编译时位于CLASSPATH上,编译器是否需要Z.class中的字节码才能编译A.java(如果需要,将构建Z.class) ,来自Z.java),还是Z.java足以满足编译器的需要?

The compiler will compile all .java files as required. 编译器将根据需要编译所有.java文件。 You need only provide the .java but it must compile (ie. its dependancies must be available) However if you use a .class file not all of its dependancy need to be available to compile A. 您只需要提供.java但它必须编译(即它的依赖项必须可用)但是如果您使用.class文件并不是所有的依赖都需要可用于编译A.

My overall confusion can be summarized as follows. 我的整体困惑可归纳如下。 It seems that the full [byte]code for Z needs to be present TWICE - once during compilation, and a second time during runtime - 似乎Z的完整[byte]代码需要存在TWICE - 一次在编译期间,第二次在运行时 -

Technically a class contains byte-code and meta-data such a method signatures, fields and constants. 从技术上讲,类包含字节码和元数据,例如方法签名,字段和常量。 None of the byte-code is used at compile time, only the meta-information. 在编译时不使用字节代码,只使用元信息。 The byte-code at compile time does not need to match what is used at runtime. 编译时的字节代码不需要与运行时使用的字节代码匹配。 (The signatures/fields used do) It is just simpler to have one copy of each class, but you could use a stripped down version at compile time if you needed to for some purpose. (使用的签名/字段可以)每个类的一个副本更简单,但如果您出于某种目的需要,可以在编译时使用精简版本。

and that this must be true for ALL classes referenced by a Java program. 并且对于Java程序引用的所有类必须为true。 In other words, every single class must be downloaded/present TWICE. 换句话说,每个类必须下载/呈现TWICE。 Not a single class can be represented during compile time as just a header file (as it can be in C++). 在编译期间,不能将单个类表示为头文件(因为它可以在C ++中)。

It only needs to be downloaded once as it sits in a repository or somewher on you disk. 它只需要下载一次,因为它位于存储库中或某些磁盘上。 The interfaces like the headers may be all you need at compile time and these could be a seperate library, but typically it is not as it is just simpler to have a single archive in most cases (OSGi is the only example I know of where it is worth seperating them) 像标题这样的接口可能就是你在编译时需要的所有东西,它们可能是一个单独的库,但通常它并不是因为在大多数情况下只有一个存档更简单(OSGi是我知道它在哪里的唯一例子)值得分开他们)

Your summary is correct, however I would like to add that if you compile to a jar, then the jar will contain Z ( and if Z is a jar only the files inside the Z jar that are needed. 你的摘要是正确的,但我想补充一点,如果你编译成一个jar,那么jar将包含Z(如果Z是一个jar,只需要Z jar中需要的文件。

However the same Z can be used for both compile and runtime. 但是,相同的Z可用于编译和运行时。

Simply put, no. 简单地说,不。 If you look at say JDBC code it is compiled against an interface, which for this purpose acts like a header file, and uses reflection to pull in the right implementation at runtime. 如果你看一下说JDBC代码,它是针对一个接口编译的,为此目的就像一个头文件,并使用反射在运行时引入正确的实现。 The drivers do not need to be present at all on the build machine, though these days a cleaner way to do this kind of thing is via a dependency injection framework. 驱动程序根本不需要在构建机器上存在,尽管现在更简洁的方法是通过依赖注入框架。

In any case, there's nothing stopping you from compiling against one 'header' class file and then running against the actual class file (Java is mostly dynamically linked) but this just seems to be making extra work for yourself. 在任何情况下,没有什么能阻止你编译一个'header'类文件,然后针对实际的类文件运行(Java 主要是动态链接的),但这似乎为你自己做了额外的工作。

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

相关问题 是否应通过“导入”作用域将所有第3方jar依赖项引入Maven? - Should all 3rd-party jar dependencies be introduced to Maven via 'import' scope? Leiningen父母>子女>第三方图书馆依赖性错误 - Leiningen Parent > Child > 3rd-Party Library Dependency Errors 在解决依赖关系之前,使用Maven安装第三方依赖关系 - Install a 3rd-party dependency with maven before dependencies are resolved Maven:将第三方jar的导出jar添加到manifest中的classpath - Maven: Export jar with 3rd-party jars added to classpath in manifest 安装具有第三方非mvn jar依赖项的第三方非mvn jar - Install a 3rd-party non-mvn jar that has 3rd-party non-mvn jar dependencies 如何将现有的第三方JAR集合上传到Gradle中的Maven服务器? - How to upload an existing collection of 3rd-party Jars to a Maven server in Gradle? 使用maven-android-plugin不能将第三方jar包含到Android应用程序中 - Cannot include 3rd-party jars into Android application with the maven-android-plugin 如何为 Intellij 和/或 VS Code 添加依赖项/第三方 java 库到 Maven 中? - How do I add dependencies/3rd party java libraries into Maven for Intellij and/or VS Code? 获取 Maven 中使用的所有 3rd 方依赖项模块 - Get all 3rd Party dependencies module is using in Maven Maven 使用 .class 和 .java 文件创建 jar 文件 - Maven create jar file with both .class and .java files
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM