Do not understand following use of -classpath by javac - java

I am not very clear with the following question from SCJP Book (I read the solution and explanation though) ..
Consider the following directory structure :-
foo --> test --> xcom --> A.class, B.java
Here foo, test and xcom are directories. A.class and B.java are the files in xcom directory.
Following are the source codes of corresponding files:-
A.java
package xcom;
public class A { }
B.java
package xcom;
public class B extends A { }
The default classpath is /foo.
Now, in order to compile B.java, I keep my current directory as test and give :-
javac -classpath xcom xcom/B.java
Here I give the classpath as xcom which has A.class. But still it does not find class A. Why is it so??

If your classes are in package xcom, then your classpath needs to be at the directory directly above that. In this case, the classpath should be foo/test.
And if your current directory is foo/test, then this should be your javac:
javac -classpath . xcom/B.java

Because you have to specify classpath root to -classpath argument, like javac -classpath . xcom/B.java. To compile class B java compiler requires class A, it tries to locate class A file in {classpathroot}/xcom/.
Note: . - is a current directory

I think the root cause here is a misunderstanding of a "fully-qualified name" in Java.
The fully-qualified names of your two classes are xcom.A and xcom.B. Their source is in files A.java and B.java in a directory named xcom; the fully-qualified names dictate the directory structure. When you are going to use the files, either to compile them or run them, the classpath contains one or more locations from which the fully-qualified names can be found; so java is looking for xcom\A.java and xcom\B.java (when compiling) and xcom\A.class and xcom\B.class (when running).
That is why the classpath needs to specify the directory that contains xcom.
As you progress to more complex environments: the classpath can be a list of such locations; each location is separated by a semicolon on windows and a colon on unix systems. Each location can be a directory, as you've already seen, but it can also be a jar file. jar files are in zip file format, and zip files have a directory structure just like disks do. So you could zip up your class files, maintaining their xcom parent (but not their full paths), and specify the jar file in the classpath instead of a directory.
I know the question was already answered somewhat, but thought you might like the background explanation as well.

Related

Ambiguity with package statement in java

Consider the following code:
package com.a.b;
class Test {
public static void main(String[] args) {
System.out.println("Hello to the world of packages");
}
}
I've compiled the program like so:
javac Test.java
This created Test.class file in the current working directory. How should I run the program now? I tried:
java Test
but I'm getting a "No class def found error". If I compile this way:
javac -d . Test.java
It's creating directory structure, then I'm able to run through
java com.a.b.Test
If I can compile without directory hierarchy, why can't I execute?
In your first command:
javac Test.java
It compiles fine because there are no errors and places the Test.class file in the current directory, because that's where Test.java resides, as per the documentation:
If the -d option is not specified, then javac puts each class file in the same directory as the source file from which it was generated.
The source file is in the current directory so the class file is placed in the current directory. Now when you execute like so:
java Test
There's an error because you must use the fully qualified class name. You specified a package, and even though it's in the current directory, you still must use the fully qualified name to specify where it is. Without the full name, Java can't find it an execute it, thus the error. You can do the following:
java com.a.b.Test
Java will find it appropriately and all will execute fine.
Now, I would recommend using the -d option to correctly place your class files for organization. I would also recommend actually creating the packages you specify, so put your Test.java file in the directory ./com/a/b.
You must always run your Java program with the fully qualified class name:
It doesn't matter whether you compile it using the javac -d option.
So, in your case, it will be:
java com.a.b.Test
It is a best practice to compile it with the -d option and store .class files in the proper directory structure as per the package name.
Update
Also, ensure your current directory is in the class-path.
Try running this:
java -cp . com.a.b.Test
Update 2
When the -d option is not used with javac, the class files are created in the current directory. You will have to move/copy the class file(s) manually to the appropriate directory and then execute them. The -d option is a short cut of achieving this.
Java search for classes in classpath. By default classpath contains only currrent directory.
When Java search for class it iterates thru classpath element. If element is directory it search file with name of the class end extension .class in some subdirectory. To be precise this subderectory is found by replasing dots to directory separation simbol (/ or \ depending on your operation system) and resolving result.
1) Add your class to the java build-path
2) Run it with the full path.

Compiling a java file using javac and the command line

I am trying to learn more about javac and how to use developer tools for Java using the command line.
As far as I understood, the option -classpath is needed to specify the path where javac searches for our classes and resource files, if we are not in the current directory, because usually the class path is set to our current working directory.
This is my current working directory:
/Users/user1/Desktop
And I am trying to compile a .java file which is in:
/Users/user1/Desktop/PF/
and the file is called MainClass.java.
I am trying to compile it using the following command:
javac -classpath /PF MainClass.java
But it does not seem to work, in fact I keep receiving the following:
javac: file not found: MainClass.java
Usage: javac <options> <source files>
use -help for a list of possible options
What am I doing wrong?
Classpath is for .class files, not for .java files.
javac command needs correct path to the .java file to compile it. So
javac ./PF/MainClass.java
Will create the class file in current directory.
If your MainClass.java depends on any class files to compile correctly, then you put those class/jar files in classpath.
That isn't how the classpath works. You use the classpath to point to classes that your Java file needs in order to compile. You don't use the classpath to point to the Java file itself.
Either go into the PF directory and do this:
javac MainClass.java
That will create the MainClass.class file inside the PF directory. If instead you want to create the MainClass.class file on your desktop, then from your desktop, do this:
javac PF/MainClass.java
-classpath
Specifies the path javac uses to look up classes needed to run javac
or being referenced by other classes you are compiling. Overrides the
default or the CLASSPATH environment variable if it is set.
Directories are separated by colons. It is often useful for the
directory containing the source files to be on the class path. You
should always include the system classes at the end of the path.
class path is used to specify the compiled sources that need to be used in your class. For example in this code if you are accessing another class then you should specify the location of the compiled sources of the that class.
In your case if don't have any class dependency then simply remove classpath option and compile using[navigate inside folder]
javac Mainclass.java
Remove the -classpath. And if you are in the place where the java file is required (which currently you arent) you can remove that PF/ too.

java compiling from the command line

I am an experienced programmer, but haven't used Java in years - mostly C# - and used an IDE in the past. I'm trying to compile some code from the command line on my Mac, but can't get my test file to find my source code. I'm assuming the problem lies somewhere in the space of packages, file structure, classpaths, and import statements - but I've put a couple hours in (including hunting on Stack Overflow) and am still stuck.
Here's what I have:
Directory structure:
ProjectName
|
--src
|
--SourceClass
--test
|
--SourceClassTest
--external
|
--testng-6.8.7.jar
My SourceClass looks like this:
package ProjectName;
public class SourceClass<T>{
}
Very simple. Obviously, there will be more - but I wanted to start with making sure I had all this setup stuff correct before I actually did coding.
My test class looks like this:
package ProjectName;
import java.util.*;
import org.testng.Assert;
import org.testng.annotations.*;
public class SourceClassTest{
#Test
private void createEmptySourceClass(){
SourceClass<Object> sourceClass = new SourceClass<Object>();
Assert.assertTrue(sourceClass.isEmtpy());
}
}
The sourceClass compiles with no issue with "javac src/*.java", run from the "ProjectName" directory. I want to see this fail with an error along the lines of "SourceClass doesn't have an isEmpty() method", but instead I run javac like this from the "ProjectName" directory:
javac test/*.java -classpath external/testng-6.8.7.jar
and get this exception:
test/SourceClassTest.java:12: error: cannot find symbol
SourceClass<Object> tree = new SourceClass<Object>();
^
symbol: class SourceClass
location: class SourceClassTest
test/SourceClassTest.java:12: error: cannot find symbol
SourceClass<Object> sourceClass = new SourceClass<Object>();
^
symbol: class SourceClass
location: class SourceClassTest
2 errors
I've tried a lot of things -adding an import statement, adding a sourcepath to the javac command, compiing the sourceClass as a jar and putting it in the bin directory then adding that to the classpath, but I can't get the test to find the SourceClass symbols.
Any idea what I am missing here?
It works if you compile into a separate target directory. E.g,
mkdir target
javac -d target/ src/*.java
javac -classpath target/ test/*.java
When you do javac src/*.java, it will create the .class file in the src directory itself. By default, any classes you reference are assumed to be in the same package. So even if you add src/ to the classpath, it looks for src/ProjectName/SourceClass.class, which it does not find. When you pass the -d target/ option, it creates the proper package hierarchy, so and finds the class.
Relevant documentation from the javac official doc:
You should arrange source files in a directory tree that reflects
their package tree. For example, if you keep all your source files in
C:\workspace, the source code for com.mysoft.mypack.MyClass should be
in C:\workspace\com\mysoft\mypack\MyClass.java.
By default, the compiler puts each class file in the same directory as
its source file. You can specify a separate destination directory with
-d (see Options, below).
...
...
-d directory Set the destination directory for class files. The directory must already exist; javac will not create it. If a class is
part of a package, javac puts the class file in a subdirectory
reflecting the package name, creating directories as needed. For
example, if you specify -d C:\myclasses and the class is called
com.mypackage.MyClass, then the class file is called
C:\myclasses\com\mypackage\MyClass.class. If -d is not specified,
javac puts each class files in the same directory as the source file
from which it was generated.
Note: The directory specified by -d is not automatically added to your
user class path.
My guess is it can't find SourceClass because the file defining that class is under src, and you didn't mention that directory in your javac command line.
If I were you, I would change the file hierarchy to this:
ProjectName/src/ProjectName/SourceClass.java
ProjectName/src/ProjectName/SourceClassTest.java
ProjectName/external/testng-6.8.7.jar
Then run javac src/ProjectName/*.java -classpath external/testng-6.8.7.jar.
Or keep the file hierarchy the way it is, and run javac src/*.java test/*.java -classpath external/testng-6.8.7.jar
The accepted answer is correct, but it misses one critical point: when javac is asked to compile *.java (as opposed to foo.java, and then foo2.java ...) it treats them as a single package and accepts references between them.
That's the magic. Other languages do this less implicitly with header files.
Even after reading this post, it took me some time to figure that out, against my inherent assumption that a program running singly on files one after the other would (should) produce the same result as running that program on a group of files. My bad; the * is NOT a mere convenience, but critical.

javac : Compiling a .java file which uses other classes in it

HI i have 3 java files
a.java
b.java
c.java
I managed to generate .class files for both a and b using
javac example/a.java
javac example/b.java
but when i do the same for c.java I get the error
error: cannot find symbol b and c
Any suggestions on how i could solve this problem ?
All the java files are in the same folder
You have to have classes a and b in your classpath when you try to compile class c. This allows the compiler to verify that they exist, figure out what methods they have, etc.
javac is pretty sensitive to package names and classpaths. The easiest thing to do is to compile all three at the same time like so javac example/a.java example/b.java example/c.java.
If you go to the parent directory of example (let's call it src), then you can run the following:
javac -cp src src/example/c.java
The reason you have to do it this way is because your classes have their packages listed as example. Because of your package name, javac is looking for the example directory in its classpath, where it expects to find a.class and b.class.
Presumably you're not in the example/ directory when you run javac. Try
javac -cp example c.java
Or just cd into that directory. The classpath is not automatically resolved for the classes c.java depends on.

Java: class resolved?

I hope this question is not repeated. But just can't find answer anywhere:
I have ONE folder containing two files one A.java another B.class.
Now in A.java I am trying to declare
public class A extends Applet{
...
B aB;
}
The compiler gives me:
B cannot be resolved to a type
I read a lot of posts that say if the files are in the same folder, I don't need to import. Could anyone help me to "resolve" this problem?
Thanks much appreciated!
-----------SOLVED! - SEE ANSWER BELOW------------------
The .class files need to reside in a directory referenced by the classpath variable. Usually you put your .java files in one directory (src), compile to another directory (bin) and have external .class files in a third directory (lib). The commands will look like this:
# compile
javac -sourcepath src -classpath lib -d bin
# run
java -classpath bin:lib A
Using an IDE like eclipse should help a lot here as it takes care of most of the details
The simple case that you've posted works for me. I'd check the following things:
Are you sure that B.class is present in the same folder as A.java?
Are you running javac from that folder?
Have you typed the class name B correctly everywhere in your program? This includes capitalization, as Java identifiers are case sensitive.
Are there any package declarations in your program? If there are, none of this is going to work, since you're implicitly using the default package by just throwing everything into a folder.
The compiler looks for *.class file in its class path. It will only look for *.java files in the same source directories. You need to set the class path to include the directory.
Or you could use an IDE which sets all this up for you and saves a lot time in the process.

Categories

Resources