Mastering the java CLASSPATH

本文详细解析了Java类路径的原理与应用,包括如何在命令行中指定类路径、类加载器的工作方式以及如何利用系统类路径进行高效类查找。通过实际例子,展示了类路径配置、JAR文件的引用、多目录搜索以及与系统类路径的整合,旨在帮助开发者更好地理解和管理Java项目的类依赖。

非常好的一篇文章,解释了classpath的一些常识问题。

原文http://kevinboone.net/classpath.html


几个常见的关于classpath的问题,大家可以思考一下,并在下面的文章中寻找答案。

1,为什么在使用jar时,为什么需要在classpath中指定 -classpath /root/lib/1.jar? 可以让java class loader自己去搜索指定目录下的所有jar包吗?

2,-classpath /root/lib/test 时,class loader会去搜索 /root, /lib下的所有jar包或class文件吗?所有test下的子目录呢?

3,在-classpath中指定多个时,用:分割。这时load class有先后顺序吗?

4,在-classpath 中指定某个目录时,如果该目录下包含多个class文件,每次load class的先后顺序固定吗?


The significance of the class search path

An understanding of the class search path is important for all Java developers.However, the widespread use of integrated development tools has concealed thetechnicalities for so long that there is a widespread lack of comprehension, evenamong experienced developers. The problem is particularly acute with development ofdistributed applications, as the system which will run the application is likely tobe configured rather differently from the one on which development takes place.

This article describes in detail how the Java compiler and the JVM use the classsearch path to locate classes when they are referenced by other Java code. Itdoes this with reference to a very simple example, which uses two classesin the same package. We will see how various operations to compile these twoclasses succeed and fail, depending on the class path setting.

To make things absolutely clear, we will use only simple command-line toolsto carry out the compile operations. Interactive development tools have theirown ways of manipulating the class path, which vary from product to product.

There is no fundamental difference between the way that the Java compilersearches for classes, and the way that the JVM does it at run time. However,the compiler has the ability to compile classes from source code, wherethe JVM does not. In the examples below we will use the compiler, butsimilar issues apply at run time.

The example

This example has two trivial classes: com.web_tomorrow.CPTest1 and com.web_tomorrow.CPTest2, which are listed below.
package com.web_tomorrow;
public class CPTest1
{
public static void main(String[] args)
  {
  System.out.println ("Run CPTest1.main()");
  }
}

package com.web_tomorrow;
public class CPTest2
{
public static void main(String[] args)
  {
  System.out.println ("Run CPTest2.main()");
  CPTest1 cpt1 = new CPTest1();
  }
}
One of the most fundamental rules of Java code organization is that `package name = directory name'. We will begin by setting up a directorystructure that matches the package assignment of these two classes.The classes are in a package com.web_tomorrow, so we must createthe directory com/web_tomorrow to contain the source code.
[root]
  com
    web_tomorrow
      CPTest1.java
      CPTest2.java
In this document I will use the notation [root]' to mean whatever directorycontains the structure described above', that is, the root of the directory layout.This will vary, of course, according to how you install the files.

Basic principles

Let's try to compile CPTest1.java on its own using the command-line javac program. To disable the class searchpath completely (so any existing setting does not interfere with theexample), we can run javac with the option ` -classpath ""'.

As a first attempt, let's change directory to the location of CPTest1.java,and try to compile it by specifying its name on thejavac command line.

cd [root]/com/web_tomorrow
javac -classpath "" CPTest1.java

这里加一句:The class path tells the JDK tools and applications where tofind third-party and user-defined classes -- that is, classes thatare not extensions or part of the Java platform.

因此对于上面这种仅使用了java core的代码来说,不需要另外指定classpath了。

This operation succeeds, because the compiler is able to find CPTest1.java(it is in the working directory), and becauseCPTest1 does notreference any other classes. The output file,CPTest1.class ends up in thesame directory as CPTest1.java because, again, you haven't given thecompiler information to do anything else. So far so good.Now let's try the same thing withCPTest2. Still in the `web_tomorrow'directory, execute this command:

javac -classpath "" CPTest2.java
This operation should fail, even though the directory is the same as the previous step,and CPTest1 and CPTest2 are in the same package. The error message will be something like this:
PTest2.java:7: cannot resolve symbol
symbol  : class CPTest1  
location: class com.web_tomorrow.CPTest2
  CPTest1 cpt1 = new CPTest1();
  ^
The difference between this case and the previous, successful, one is that CPTest2 contains a reference to CPTest1:
  CPTest1 cpt1 = new CPTest1();
What is going on here? When the compiler encounters the reference to CP1Test here, it assumes that this is a class in the samepackage as CP2Test that is is currently compiling. This isa correct assumption. So the compiler needs to find com.web_tomorrow.CP1Test. But it has nowhere to look, aswe have explicitly set the class search path to "" (i.e., nothing).

You might think this problem can be resolved by telling the compiler tolook in the current directory. The standard symbol for `current directory'is a single period (.) in both Unix and Windows systems. So try somethinglike this:

javac -classpath "." CPTest2.java
This fails in exactly the same way as the previous example. The problem now is that although CPTest1.java is in the currentdirectory, the class that it implements is not just CPTest1,but com.web_tomorrow.CPTest1. The compiler will look fora directory com/web_tomorrow below the current directory.So, overall, it is looking for a Java source or class file in the directory [home]/com/web_tomorrow/com/web_tomorrow which, of course,does not exist.

To make this compile operation work, we need to make the class search pathreference not the directory containingCPTest1, but a directoryroot from whichCPTest1 can be located by the compiler followingthe standard Java `package name = directory name' rule. This shouldwork, although it's rather ugly:

javac -classpath "../.." CPTest2.java
Before seeing how we can make this less ugly, consider this example (stillin the same directory):
javac -classpath "" CPTest1.java CPTest2.java
This also works, even though the class path is empty. This is because the Java compiler will look for references betweenany source code explicitly listed on the command line. If there are many classes, allin the same directory, we can simplify this to:
javac -classpath "" *.java 
The `*.java' expands to a list of all the .java files in the current directory.This explains why compiling many files in one operation often succeeds where attemptsto compile a single file fails.

A more convenient way to compile CPTest2 on its own is like this:

cd [root]
javac -classpath "." com/web_tomorrow/CPTest2.java
In this example we specify the full path to CPTest2.java, but include`.' in the -classpath option. Again, we aren't telling the compiler tolook for files in the current directory, we are telling it to begin a class searchfrom the current directory. Because the class we are looking for is com.web_tomorrow.CPTest1, the compiler will search in ./com/web_tomorrow (that is, the directory com/web_tomorrowbelow the current directory). This is exactly where CPTest1.java islocated.

In fact, even though I only specified CPTest2 on the command line, thispractice does in fact lead to the compilation ofCPTest1 as well.The compiler finds the.java file in the right place, but it can't tellwhether this Java source really implements the right class, so it has to compileit. But note that if we do this:

cd [root]
javac -classpath "." com/web_tomorrow/CPTest1.java
it does not cause a compilation of CPTest2.java, because the compilerdoes not need to know anything about CPTest2 to compile CPTest1.

.class files separate from .java files

The examples described so far, when successful, place the output .classfiles alongside the .java files from which they were generated. Thisis a simple scheme, and very widely used. However, many developers like tokeep the source tree free of generated files, and must therefore tell the Javacompiler to maintain separate directories for .class files. Let'ssee what impact this has on the class search path.

To begin we will need to delete any .class files lurking around afterthe previous examples. We will also contain a new directoryclassesto contain the generated.class files. The procedure at the command line would be something like this:

cd [root]
rm com/web_tomorrow/*.class
mkdir classes
Don't forget to swap the `/' characters for '\' if you are using a Windows system.The directory structure now looks like this.
[root]
  com
    web_tomorrow
      CPTest1.java
      CPTest2.java
  classes
Let's compile CPTest1.java, specifying classes as thedestination directory (using the -d option):
cd [root]
javac -d classes -classpath "" com/web_tomorrow/CPTest1.java 
This should succeed, but you should notice that the .class fileshave not been placed into the classes directory at all.Instead, we have a new directory structure like this:
[root]
  com
    web_tomorrow
      CPTest1.java
      CPTest2.java
  classes
    com
      web_tomorrow
        CPTest1.class
What has happened is that the compiler has created a directory structure to matchthe package structure. It has done this to be helpful, as we shall see. When wecome to compile CPTest2.java we have two choices. First, we cancompile it as described above, allowing the compiler to compile CPTest1as part of the process. Alternatively, we can compile it and use the -classpathoption to refer to the compiler to the .class file generated in theprevious step. This method is superior, as we don't have to repeat the compilation of CPTest1.
cd [root]
javac -d classes -classpath classes com/web_tomorrow/CPTest2.java 
By doing this, we end up with this directory structure.
[root]
  com
    web_tomorrow
      CPTest1.java
      CPTest2.java
  classes
    com
      web_tomorrow
      CPTest1.class
      CPTest2.class
Of course we could have compiled both .java files in the same command,and got the same result.

JARs on the classpath

The java compiler and run-time can search for classes not only in separate files,but also in `JAR' archives. A JAR file can maintain its own directory structure,and Java follows exactly the same rules as for searching in ordinary directories.Specifically, `directory name = package name'. Because a JAR is itself a directory,to include a JAR file in the class search path, the path must reference the JARitself, not merely the directory that contains the JAR. This is a verycommon error. Suppose I have a JAR myclasses.jar in directory /myclasses. To have the Java compiler look for classes in this jar,we need to specify:
javac -classpath /myclasses/myclasses.jar ...
and not merely the directory myclasses.

Multiple class search directories

In the examples above, we have told javac to search in only onedirectory at a time. In practice, your class search path will containnumerous directories and JAR archives. The -classpathoption to javac and java allows multiple entries to be specified, but notice that the syntax is slightly differentfor Unix and Windows systems.

On Unix, we would do this:

javac -classpath dir1:dir2:dir3 ...
whereas on Windows we have:
javac -classpath dir1;dir2;dir3 ...
The reason for the difference is that Windows uses the colon (:) character as partof a filename, so it can't be used as a filename separator. Naturally the directory separator character is different as well: forward slash (/) for Unix andbackslash (\) for Windows.

System classpath

Rather than specifying class search path on the javac command line, wecan make use of a `system' class path. This is the class path that will beused by both the Java compiler and the JVM in the absence of specific instructionsto the contrary. In both Unix and Windows systems, this is done by setting an environmentvariable. For example, in Linux with the bash shell:
CLASSPATH=/myclasses/myclasses.jar;export CLASSPATH 
and in Windows:
set CLASSPATH=c:\myclasses\myclasses.jar
This procedure is fine for short-term changes to the system CLASSPATH, but ifyou want these changes to be persistent you will need to arrange this yourself.Details vary from system to system. On a Linux system, for example, I wouldput the commands in the file .bashrc in my home directory. OnWindows 2000/NT there is a `Control Panel' page for this.

Setting the system CLASSPATH is a useful procedure if you have JARs full of classes that you use allthe time. For example, if I am developing Enterprise JavaBean (EJB)applications using Sun's J2EE `Reference Implementation', all the EJB-relatedclasses are in a JAR called `j2ee.jar' that comes with thedistribution. I want this JAR on the class search path all the time.In addition, most people want to ensure that the current directoryis on the search path, whatever the current directory happens to be.So in my .bashrc file I have this line:

CLASSPATH=/usr/j2ee/j2ee.jar:.;export CLASSPATH 
where the .' indicates current directory'.

It is easy to overlook that the -classpath optionon the command linereplaces the default, system class path; itdoes not add to it. So what should I do if I want to set the class pathto include the default system classpathplus some other entries?I could simply use the -classpath option and list thedefault entries in addition to my extras. However, a better way is toreference the CLASSPATH environment variable. The syntax for thisis different — of course — on Windows and Unix systems.On Unix:

javac -classpath $CLASSPATH:dir1:dir2 ...
where $CLASSPATH expands to the current setting of the CLASSPATHenvironment variable. On Windows:
javac -classpath %CLASSPATH%;dir1:dir2 ...
Finally, please note that if directories in your class search path havespaces in their names, you may have to use double-quotes on the commandline to prevent the CLASSPATH being split up. For example:
javac -classpath "%CLASSPATH%";dir1:dir2 ...


下面是另外一个帖子,关于如何找到程序使用的classpath:

http://blog.youkuaiyun.com/onlyqi/article/details/8194357

如上面文章所诉,我们通常不会使用默认的CLASSPATH环境变量,而是在运行java程序时,使用-classpath参数来指定class path。因此查看系统进程,就可是知道正在运行的java程序使用的-classpath参数是什么。


另外两篇官网的文章,介绍的更全面一些,必看。

Setting the class path

http://download.java.net/jdk8/docs/technotes/tools/solaris/classpath.html

How Classes are Found

http://download.java.net/jdk8/docs/technotes/tools/findingclasses.html

【完美复现】面向配电网韧性提升的移动储能预布局与动态调度策略【IEEE33节点】(Matlab代码实现)内容概要:本文介绍了基于IEEE33节点的配电网韧性提升方法,重点研究了移动储能系统的预布局与动态调度策略。通过Matlab代码实现,提出了一种结合预配置和动态调度的两阶段优化模型,旨在应对电网故障或极端事件时快速恢复供电能力。文中采用了多种智能优化算法(如PSO、MPSO、TACPSO、SOA、GA等)进行对比分析,验证所提策略的有效性和优越性。研究不仅关注移动储能单元的初始部署位置,还深入探讨其在故障发生后的动态路径规划与电力支援过程,从而全面提升配电网的韧性水平。; 适合人群:具备电力系统基础知识和Matlab编程能力的研究生、科研人员及从事智能电网、能源系统优化等相关领域的工程技术人员。; 使用场景及目标:①用于科研复现,特别是IEEE顶刊或SCI一区论文中关于配电网韧性、应急电源调度的研究;②支撑电力系统在灾害或故障条件下的恢复力优化设计,提升实际电网应对突发事件的能力;③为移动储能系统在智能配电网中的应用提供理论依据和技术支持。; 阅读建议:建议读者结合提供的Matlab代码逐模块分析,重点关注目标函数建模、约束条件设置以及智能算法的实现细节。同时推荐参考文中提及的MPS预配置与动态调度上下两部分,系统掌握完整的技术路线,并可通过替换不同算法或测试系统进一步拓展研究。
先看效果: https://pan.quark.cn/s/3756295eddc9 在C#软件开发过程中,DateTimePicker组件被视为一种常见且关键的构成部分,它为用户提供了图形化的途径来选取日期与时间。 此类控件多应用于需要用户输入日期或时间数据的场景,例如日程管理、订单管理或时间记录等情境。 针对这一主题,我们将细致研究DateTimePicker的操作方法、具备的功能以及相关的C#编程理念。 DateTimePicker控件是由.NET Framework所支持的一种界面组件,适用于在Windows Forms应用程序中部署。 在构建阶段,程序员能够通过调整属性来设定其视觉形态及运作模式,诸如设定日期的显示格式、是否展现时间选项、预设的初始值等。 在执行阶段,用户能够通过点击日历图标的下拉列表来选定日期,或是在文本区域直接键入日期信息,随后按下Tab键或回车键以确认所选定的内容。 在C#语言中,DateTime结构是处理日期与时间数据的核心,而DateTimePicker控件的值则表现为DateTime类型的实例。 用户能够借助`Value`属性来读取或设定用户所选择的日期与时间。 例如,以下代码片段展示了如何为DateTimePicker设定初始的日期值:```csharpDateTimePicker dateTimePicker = new DateTimePicker();dateTimePicker.Value = DateTime.Now;```再者,DateTimePicker控件还内置了事件响应机制,比如`ValueChanged`事件,当用户修改日期或时间时会自动激活。 开发者可以注册该事件以执行特定的功能,例如进行输入验证或更新关联的数据:``...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值