Mastering the java CLASSPATH

非常好的一篇文章,解释了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.csdn.net/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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《掌握FreeRTOS实时内核》是一本关于FreeRTOS实时内核的技术书籍。FreeRTOS是一款开源、免费的实时操作系统内核,广泛应用于嵌入式系统中。该书详细介绍了FreeRTOS内核的各个方面,帮助读者全面掌握这一实时操作系统。 书中首先介绍了FreeRTOS的基本概念和特点。FreeRTOS以其低开销、高可伸缩性和易用性而备受欢迎。读者将了解到FreeRTOS如何实现多任务管理、任务调度和资源管理,以及如何充分利用处理器的性能。 其次,书中深入探讨了FreeRTOS的任务管理和调度机制。读者将学习如何创建任务、控制任务的优先级和时间片分配,以及任务的挂起和终止。同时,书中还介绍了如何利用FreeRTOS的定时器和调度策略来实现实时性需求。 此外,书中还涉及了FreeRTOS的中断处理和任务通信机制。读者将了解如何处理中断,并通过信号量、消息队列和事件标志等机制实现多任务之间的通信与同步。这些内容对于读者理解嵌入式系统的并发编程非常重要。 最后,书中还包含了一些实际案例和示例代码,帮助读者更好地理解和应用FreeRTOS。通过实践,读者可以掌握FreeRTOS内核的使用技巧和调试方法,加深对实时操作系统的理解。 综上所述,《掌握FreeRTOS实时内核》是一本全面介绍FreeRTOS的技术书籍,适合那些希望深入了解和应用FreeRTOS内核的嵌入式开发人员。通过学习这本书,读者可以掌握FreeRTOS的工作原理和使用技巧,提高嵌入式系统开发的能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值