Using classpaths - java

I plan on becoming a certified Java programmer and am studying from the Sierra-Bates book. I had a question about classpaths. Do classpaths need to find only the supporting classes of the class I'm running/compiling, or the supporting classes and the class itself? Also, when I'm getting classes in packages from classpaths, is it legal to just put the adress of the file(the path to it), instead of putting it's root package. Thanks.

1 - a classpath has to give access to each class that needs to run in your program. That would include the main class and any classes it calls and those they call. If there is some code in one of those classes that is never called, in many cases, you don't need to have the classes referenced by the uncalled code.
2 - you have to put the root of the packages in the classpath. So a class "com.bob.myprog.Main" would need to have the class path point to the folder where the "com" package/folder lies. It will need to contain a "bob" folder and "bob" will need to contain a "myprog" folder with "Main.class" in it.

Classpath has to contain both the supporting classes and the class itself.
However, sometimes you can run a single file without specifying classpath (and it will work).
As specified in http://docs.oracle.com/javase/tutorial/essential/environment/paths.html :
The default value of the class path is ".", meaning that only the
current directory is searched. Specifying either the CLASSPATH
variable or the -cp command line switch overrides this value.
Therefore, if you have a class MyClass compiled in the current directory, the following will work:
java MyClass
while pointing classpath to another directory will lead to an error (classpath no longer contains MyClass):
java -cp lib MyClass
When you have a class in a package, it is not enough to put the address to the class file in the classpath. According to SCJP Sun Certified Programmer for Java 5 Study Guide:
In order to find a class in a package, you have to have a directory in
your classpath that has the package's leftmost entry (the package's
"root") as a subdirectory.

Related

Why do java source files require package declarations?

I think I am failing to understand java package structure, it seemed redundant to me that java files have a package declaration within, and then are also required to be present in a directory that matches the package name. For example, if I have a MyClass.java file:
package com.example;
public class MyClass {
public static void main(String[] args) {
System.out.println("Hello, World");
}
}
Then I would be required to have this file located in com/example, relative to the base directory, and I would execute java com.example.MyClass from the base directory to run it.
Why wouldn't the compiler be able to infer the package name by looking at the directory structure? For example, if I compiled the file from the base directory javac com\example\MyClass.java, I am not understanding why the MyClass.java wouldn't implicity belong to the com.example package.
I understand there is a default package, but it still seems that the package declaration in the source file is redundant information?
As you (implicitly) acknowledged, you are not required to declare the name of a package in the case of the default package. Let us put that quibble aside ...
The reason for this seeming redundancy is that without a package declaration, the meaning of Java1 source code would be ambiguous. For example, a source file whose pathname was "/home/steve/project/src/com/example/Main.java" could have 7 different fully qualified names, depending on how you compiled the code. Most likely, only one of those will be the "correct" one. But you wouldn't be able to tell which FQN is correct by looking at (just) the one source file.
It should also be noted that the Java language specification does not require you to organize the source code tree according to the packages. That is a requirement of a (large) family of Java compilers, but a conformant compiler could be written that did not require this. For example:
The source code could be held in a database.
The source code could be held in a file tree with random file names2.
In such eventualities, the package declaration would not be duplicative of file pathnames, or (necessarily) of anything. However, unless there was some redundancy, finding the correct source "file" for a class would be expensive for the compiler ... and problematic for the programmer.
Considerations like the above are the practical reason that most Java tool chains rely on file tree structure to locate source and compiled classes.
1 - By this, I mean hypothetical dialect of Java which didn't require package declarations.
2 - The compiler would need to scan the file tree to find all Java files, and parse them to work out which file defined which class. Possible, but not very practical.
Turn the question on its head:
Assume that the package statement is the important thing - It represents the namespace of the class and belongs in the class file.
So now the question is - Why do classes have to be in folders that match their package?
The answer is that it makes finding them much easier - it is just a good way to organize them.
Does that help?
You have to keep in mind that packages do not just indicate the folder structure. The folder structure is the convention Java adopted to match the package names, just like the convention that the class name must match the filename.
A package is required to disambiguate a class from other classes with the same name. For instance java.util.Date is different from java.sql.Date.
The package also gives access to methods or members which are package-private, to other classes in the same package.
You have to see it the other way round. The class has all the information about itself, the class name and the package name. Then when the program needs it, and the class is not loaded yet, the JVM knows where to look for it by looking at the folder structure that matches the package name and the class with the filename matching its class name.
In fact there's no such obligation at all.
Oracle JDKs javac (and I believe most other implementations too) will happily compile your HelloWorld class, no matter what directory it is in and what package you declare in the source file.
Where the directory structure comes into the picture is when you compile multiple source files that refer to each other. At this point the compiler must be able to look them up somehow. But all it has in the source code is the fully qualified name of the referred class (which may not even have been compiled yet).
At runtime the story is similar: when a class needs to be loaded, its fully qualified name is the starting point. Now the class loader's job is to find a .class file (or an entry in a ZIP file, or any other imaginable source) based on the FQN alone, and again the simplest thing in a hierarchical file system is to translate the package name into a directory structure.
The only difference is that at runtime your "standalone" class too has to be loaded by the VM, therefore it needs to be looked up, therefore it should be in the correct folder structure (because that's how the bootstrap class loader works).

Java Reflection library - using Class.forName() without package info

I have a project which requires creating Classes dynamically at runtime, where the only information available is the Class name in String form. I'm testing right now with some dead simple Reflection library methods, but my question is, why do I have to provide a fully qualified Class name if the Classes I'm trying to 'dynamically' load are in the same directory? I'm using linux, no development environment, just all the Classes I'm trying to invoke in the same directory with no package declarations whatsoever. Do I have to set up a package system to use Reflection? Here's this little code snippet....
public class ReflectionTest {
public static void main(String[] args) {
try {
Class nodeClass = Class.forName("Node");
System.out.println(nodeClass.toString());
} catch (ClassNotFoundException cnfe) {
System.out.println("Error");
}
}
}
Now, this throws the error. But when I create an instance of Node, and then get it's fully qualified Class name with Node.getClass().getName(), I just get "Node" in return. So I don't understand why the Reflection library doesn't work the same as invoking the JVM with 'java', where if no package name is supplied it simply looks in the same directory. I'm not sure how to use this library with user-defined Classes when none of my Classes have an associated package name.
Your code should work as described. That is, if you can call new Node() you should also be able to call Class.forName("Node"). I've just tried this with a package-less class to verify and everything works as expected.
Is Node.class available in the classpath? You may get this to work by adding the current directory to the classpath.
The package name is an integral part of the java naming system. However, if your class does not declare a package, it is in the root package, the code you posted should work.
My guess: the directory is not actually in the CLASSPATH. Try adding the current directory (./) and making sure it is actually the current directory, or include the directory explicitly (absolute path) in your CLASSPATH. Refer to the docs to find out how to set CLASSPATH (environment, jvm options, runtime are your options)
It works for me using the exact ReflectionTest.java above and the following Node.java:
public class Node { }
Did you compile Node.java as well as ReflectionTest.java? Since the ReflectionTest class does not have a compile-time dependency on the Node class, javac won't automatically compile Node.class when it compiles ReflectionTest.class.
There is no concept of a directory for classes in Java. Classes are in a package, or are in the default package, and are loaded from directories or jars that must be in the classpath.
If the directory containing Node.class is in the classpath, the above code should work.
But it's a very very bad practice to use the default package. Every class should be in a package.
First of all you need to make sure that the classes that you're trying to load are in the classpath, so when launching the jvm try adding the current folder to it: java -cp . ReflectionTest
The concept of packages is to keep your stuff organized and to be able to reuse names. Providing the fully qualified name, ensures that you are using the correct Node class, and for example not org.w3c.dom.Nodeor something similar which would be implicitly shipped with java.

Packages for Beginners

When a classfile that belongs to a package,
then
package PackageName;
is included in the source code of that file.
So when jvm is invoked by writing
java PackageName.classfilename
it gets executed.
Is it that "package PackageName" guarantees the jvm that this classfile belongs to this very package?
Because if we omit the "package PackageName" statement, then jvm still finds out the class file but gives
Exception in thread "main" java.lang.NoClassDefFoundError: Classfilename
wrongname PackageName/ClassfileName
It means jvm finds out the file but there is some reason for which it considers that this classfile has a wrong name.
The package declarations on your classes must match the folder structure that you have for your code.
Packages are used by the JVM for several "tasks", from the visibility of methods, to the resolution of situations where two classes could have the same name.
A NoClassDefFoundError actually means the JVM cannot find the class with the package you gave it. If you ommit the package definition on the class, and run the program like:
java ClassFileName
The JVM will find the class, as long as you're running the java command from the folder where your class is.
Also... package names should be all lowercase and Class names should start with an Uppercase. :) Conventions are really helpful when someone else is reading your code!
Hope the comment helped.
The class file needs to exist on the file system in the same hierarchy as is defined in the package name. If you remove the package name, I believe you must have the file in the root folder of your jar to work in the "unnamed" package. Likely you removed the package line from the source file but still left the class definition inside of the PackageName folder.

the number of class files in a java package constant

I am new to java.My friend asked me this question today And i am looking for an answer to it.
How to make the number of class files in a package, constant?
i.e., even though one can access that package,they should not be able to add any new class to the exisiting package.
You want sealed packages. Once sealed, all classes from a package must come from the same JAR file. It basically boils down to adding the package to the manifest:
Name: myCompany/myPackage/
Sealed: true
See Sealing packages within a jar file
This is called sealing the package and works on the level of jar files.
From the official trail:
Packages within JAR files can be optionally sealed, which means that all classes defined in that package must be archived in the same JAR file. You might want to seal a package, for example, to ensure version consistency among the classes in your software.
To clarify: Since the classes must come from the same jar file, no one can add classes to your package, since the new classes wouldn't come from your jar file.

Java not compiling .class files under $CLASSPATH

I'm trying to figure out how organize source and class files working with packages. I found a very useful tutorial. But I still have some questions.
As far as I understood it is a good practice to have an isomorphism between name of packages and name of the directories where elements of a package are stored. For example if I have a package named aaa.bbb.ccc which contains class ddd it is a good practice to have a class file called "ddd.class" and located in "$CLASSPATH/aaa/bbb/ccc/". Did I get it right?
If it is the case, will Java compiler put *.class files into the correct directory automatically?
I was not able to get this behavior. I set the $CLASSPATH variable to "/home/myname/java/classes". I executed javac KeyEventDemo.java which contains package events;. I expected that javac will create a subdirectory events under /home/myname/java/classes and put the KeyEventDemo.class in this subdirectory.
It did not happen. I tried to help to javac and created "events" subdirectory by myself. I used javac again but it does not want to put class files under "/home/myname/java/classes/events". What am I doing wrong?
You need to use the -d option to specify where you want the .class files to end up. Just specify the base directory; javac will create any directories necessary to correspond to the right package.
Example (based on your question):
javac -d ~/java/classes KeyEventDemo.java
For example if I have a package named
"aaa.bbb.ccc" which contains class
"ddd" it is a good practice to have a
class file called "ddd.class" and
located in "$CLASSPATH/aaa/bbb/ccc/".
Did I get it right?
That's not "good practice" - this is how the Sun JDK expects things to be. Otherwise, it will not work. Theoretically, other Java implementations could work differently, but I don't know any that do.
If it is the case, will Java compiler
put *.class file into a correct
directory automatically?
Yes
What am I doing wrong?
The source code must also already follow this structure, i.e. KeyEventDemo.java must reside in a subdirectory named "events". Then you do "javac events/KeyEventDemo.java", and it should work.
It is not only good practice but a must in most cases.
consider a Java class named:
com.example.Hello
If you store it on the filesystem, it has to got to
/path/to/my/classes/com/example/Hello.java
The compiler (or at least the vast majority) will create the class file at
/path/to/my/classes/com/example/Hello.class
Personally I would not use the CLASSPATH variable to set the path but the -cp option on java. A call to the above "application" could be done with:
java -cp /path/to/my/classes com.example.Hello

Categories

Resources