自从我开始学习Java以来​​,我几乎已经知道, 清单文件中的Class-Path标头字段为可执行JAR (具有由另一个称为Main-Class清单指定应用程序起点的 JAR)指定相对运行时类路径。 一个同事最近碰到一个让我感到惊讶,因为它证明了一个问题JAR文件的清单的Class-Path条目也影响编译时类路径时包含在类路径中包含JAR在运行javac的 。 这篇文章演示了这种新变化。

Java教程的部署跟踪的“ 将类添加到JAR文件的类路径 ”部分指出:“您指定要包含在applet或应用程序清单文件的Class-Path头字段中的Class-Path 。” 同一部分还指出:“通过使用清单中的Class-Path标头,可以避免在调用Java运行应用程序时指定长的-classpath标志。” 这两个句子从本质上总结了我一直如何想到清单文件中的Class-Path头:作为包含的JAR的类路径是通过Java应用程序启动器( java可执行文件)执行的。

事实证明,JAR清单中的Class-Path条目会影响Java编译器( javac ),就像它会影响Java应用程序启动器( java )一样。 为了演示这一点,我将使用一个简单的接口( PersonIF ),一个实现该接口的简单类( Person ),以及一个简单的Main类,该类使用实现该接口的类。 接下来显示这些的代码清单。

PersonIF.java

public interface PersonIF
{void sayHello();
}

人.java

import static java.lang.System.out;public class Person implements PersonIF
{public void sayHello(){out.println("Hello!");}
}

Main.java

public class Main
{public static void main(final String[] arguments){final Person person = new Person();person.sayHello();}
}

从上面的代码清单可以看出, Main类依赖于(使用) Person类,而Person类依赖于(实现) PersonIF 。 我将把PersonIF.class文件放在其自己的名为PersonIF.jar JAR中,并将该JAR存储在(不同的)子目录中。 Person.class文件将存在于其自己的Person.jar JAR文件中,并且该JAR文件包括一个MANIFEST.MF file ,该MANIFEST.MF fileClass-Path标头引用了相对子目录中的PersonIF.jar

现在,我将尝试仅使用类路径中的当前目录从Main.java编译Main.class 。 我以前曾希望当javac无法在单独的子目录中找到PersonIF.jar时, javac会失败。 但是,它不会失败!

这让我感到惊讶。 当我没有明确指定PersonIF.class (或包含它的JAR)作为通过-cp标志提供的classpath的值时,为什么要编译此文件? 通过使用带有-verbose标志的javac可以看到答案。

javac -verbose的输出提供“ 文件的搜索路径”和“ 文件的搜索路径”。 在这种情况下,“类文件的搜索路径”很重要,因为我已经将PersonIF.javaPerson.java源文件移到了一个完全不相关的目录中,而不是在那些指定的搜索路径中。 有趣的是,即使我没有在-cp的值中指定此JAR(甚至目录),类文件的搜索路径(以及源文件的搜索路径)仍包含archive/PersonIF.jar 。 这表明Oracle提供的Java编译器考虑在类Class-Path上指定的任何JAR的MANIFEST.MFClass-Path标头中指定的类路径内容。

下一个屏幕快照演示了如何运行新编译的Main.class类,以及PersonIF.classarchive/PersonIF.jar获取依赖PersonIF.class archive/PersonIF.jar而无需在传递给Java应用程序启动程序的java -cp标志的值中指定依赖PersonIF.class 。 我希望运行时行为是这种方式,尽管坦白地说我从未尝试过,甚至从未考虑过使用其MANIFEST.MF文件没有Main-Class标头(不可执行的JAR)的JAR进行操作。 在此示例中, Person.jar清单文件未指定Main-Class头,而仅指定了Class-Path头,但是在使用java调用时仍能够在运行时使用此类路径内容。

本文的最后演示涉及从JAR文件中删除Class-Path标头和关联的值,并尝试使用javac和相同的命令行指定的classpath进行编译。 在这种情况下,包含Person.class的JAR被称为Person2.jar ,下面的屏幕快照演示了其MANIFEST.MF文件没有Class-Path标头。

下一个屏幕快照展示了使用javac现在失败的原因,这是因为,正如预期的那样,没有在类路径上显式指定PersonIF.class ,并且不再通过引用JAR的MANIFEST.MF Class-Path头使它可用。类路径。

从上一个屏幕快照中我们可以看到,源文件和类文件的搜索路径不再包含archive/PersonIF.jar 。 没有可用的JAR, javac无法找到PersonIF.class并报告错误消息:“找不到PersonIF.class类文件。”

一般观察

  • MANIFEST.MF文件中的Class-Path标头不依赖于存在于同一JAR的MANIFEST.MF文件中的Main-Class标头。

    • 带有Class-Path清单标头的JAR将使这些类路径条目可用于Java类加载器,而不管该JAR是使用java -jar ...执行还是仅放置在较大的Java应用程序的类路径上。
  • 因为在JAR清单文件中使用Class-Path的范围不限于正在执行其Main-Class JAR,所以这些类可能潜在地无意中满足了类依赖关系(即使版本不正确),而不是解析明确指定的classpath条目。 在构造带有指定Class-Path清单的JAR时,或在清单文件中使用带有Class-Path的第三方JAR时,建议谨慎。
  • 有时低估了JAR清单文件的重要性,但是该主题提醒人们了解特定JAR清单文件中的内容的有用性。
  • 本主题提醒人们可以不时通过运行javac而无需-verbose来了解其最新信息而获得的见解。
  • 每当将JAR放置在javac编译器或java应用程序启动器的类路径上时,您不仅在类路径中的那个JAR中放置了更多的类定义,还包括了更多的类定义。 您还将放置该JAR清单清单的Class-Path引用的所有类和JAR到编译器或应用程序启动器的Class-Path上。

结论

Java类加载器可以在许多地方加载用于构建和运行Java应用程序的类。 正如本文所展示的,JAR的MANIFEST.MF文件的Class-Path头是另一个影响点,可以影响类加载器在运行时和编译时加载的类。 使用Class-Path不仅不会影响“可执行”的JAR(在清单文件中指定了Main-Class标头,并使用java -jar ...运行),而且可能会影响已加载的类以进行编译以及任何Java应用程序执行,其中带有包含Class-Path标头的清单文件的JAR位于类路径上。

翻译自: https://www.javacodegeeks.com/2015/09/jar-manifest-class-path-is-not-for-java-application-launcher-only.html

JAR清单类路径不仅适用于Java Application Launcher相关推荐

  1. java launcher_JAR清单类路径不仅适用于Java Application Launcher

    java launcher 自从我开始学习Java以来​​,我几乎已经知道, 清单文件中的Class-Path标头字段为可执行JAR (具有由另一个称为Main-Class清单指定应用程序起点的 JA ...

  2. java jar 指定路径_java – 指定jar的类路径

    我正在尝试配置JAR的类路径,以便我的ResourceBundle可以从中获取属性文件. 如果我从.class文件运行它并指定-cp标志它工作正常,并且System.err.println(Syste ...

  3. clipse3.2/3.3中指定第三方包(JAR)和类路径(CLASSPATH)的几个方法(转做笔记)

    在Java类中,我们可以通过"import + 包名 + 类名"的方式引用第三方包(jar)或者第三方类(class),但你得告诉Java编译和运行环境到哪里去找这些库或者类,如果 ...

  4. java一个项目只有一个主类吗_组成Java Application的若干类中,有且仅有一个主类,只有主类中含有主方main()。...

    组成Java Application的若干类中,有且仅有一个主类,只有主类中含有主方main(). A:对 B:错 正确答案:对 解析: 组成Java Application的若干类中,有且仅有一个主 ...

  5. java jeditorpane 自动换行_JDIC 中利用WebBrowser内置浏览器到java application中 | 学步园...

    JDIC简介: JDesktop Integration Components (JDIC),是一个开源的项目,目的是构建消除本机应用程序和 Java 等价物之间差距的组件.项目组长是个中国人.该项目 ...

  6. 交叉编译指定运行时库路径_运行时vs编译时类路径

    交叉编译指定运行时库路径 这确实应该是一个简单的区别,但是我一直在回答有关Stackoverflow的许多类似问题,并且经常有人误解此事. 那么,什么是类路径? 应用程序所需的一组所有类(以及带有类的 ...

  7. 运行时vs编译时类路径

    这确实应该是一个简单的区别,但是我一直在回答有关Stackoverflow的许多类似问题,并且经常有人误解此事. 那么,什么是类路径? 应用程序所需的一组所有类(以及带有类的jar)的集合. 但是有两 ...

  8. Java Application和Java Applet

    Java Applet和Java Application 主要区别: (1)运行方式不同.Java Applet程序不能单独运行,它必须依附于一个用HTML语言编写的网页并嵌入其中,通过与Java兼容 ...

  9. Java Applet与Java Application的区别

    Java Applet与Java Application的区别 在Java语言中,能够独立运行的程序称为Java应用程序(Application).Java语言还有另外一种程序--Applet程序.A ...

最新文章

  1. php5.3中的safe_mod与magic_quotes_gpc
  2. 转载 想要在项目中引入其他项目的方法为
  3. Redis实战(四):redis的消息订阅、pipeline、事务、modules、布隆过滤器、缓存LRU
  4. np读取csv文件_pandas.read_csv函数参数详解
  5. LeetCode-Spiral Matrix-螺旋矩阵
  6. phpMyAdmin源码配置过程
  7. Identity Server 4 - Hybrid Flow - MVC客户端身份验证
  8. linux司机售票员问题
  9. 数字图像处理总复习讲义
  10. 软件项目启动ppt_一直在启动不可行的软件项目
  11. edup无线网卡驱动安装linux,UBUNTU_15.0.4 usb无线网卡驱动安装方法
  12. Java岗大厂面试百日冲刺【Day52】— 数据库8 (日积月累,每日三题)
  13. imageview显示服务器图片,imageview 直接加载图片流
  14. 如何拍背景虚化的照片_如何拍摄出突出主体(背景虚化)的照片
  15. angularjs 常用方法
  16. setTimer()函数详解
  17. 循序渐进学spring security 第八篇,如何配置密码加密?是否支持多种加密方案?
  18. 让lynda网站显示中文字幕
  19. TrustZone软硬件架构
  20. 京东生鲜全品类爬虫--往期创作整理

热门文章

  1. java打印九九乘法表——CSDN博客
  2. JavaScript实现四则运算
  3. CommonResult响应工具类封装
  4. 数组中一种数出现奇数次和两种数出现奇数次
  5. linux 无线网卡驱动桥转发,引用和完美转发
  6. XML——XSLT的一个简单荔枝
  7. DFS应用——找出无向图的割点
  8. 栈应用(中缀表达式转后缀表达式并计算后缀表达式的值)
  9. throwable_您想了解的所有Throwable
  10. spring vaadin_在Spring Boot中使用Vaadin的简介